tlp-icons

Documentation

Getting started with tlp-icons

26,278 icons in 35 categories, every one animated. One small custom element, <tlp-icon>, works in plain HTML and every framework. No dependencies.

Installation

npm

bash
npm install tlp-icons

CDN, no build step

Loads the element and fetches only the categories your page uses.

html
<script type="module" src="https://unpkg.com/tlp-icons/dist/tlp-icon.js"></script>

<tlp-icon name="bell"></tlp-icon>

Offline, one file

A classic script with every icon inside (about 2.3 MB, 390 KB gzip), in the tlp-icons-data package. Works from file://, with no network and no module loader.

bash
npm install tlp-icons-data
html
<script src="node_modules/tlp-icons-data/tlp-icons.all.js"></script>
<tlp-icon name="bell"></tlp-icon>

Basic usage

Write the element with an icon name. Find names in the icon gallery. Hover these:

bell
clock
settings
trash
cloud-rain
lock
html
<tlp-icon name="bell"></tlp-icon>
<tlp-icon name="settings" size="32" stroke="1.5"></tlp-icon>

Attributes

AttributeValuesDefaultWhat it does
nameicon name or aliasWhich icon to show.
sizenumber (px) or CSS length24Width and height (same as --tlp-size).
strokenumber2Stroke width in the 24×24 grid (same as --tlp-stroke).
triggerhover hold loop click nonehoverWhen the animation plays. hold: plays to its peak on hover, stays, returns when the mouse leaves.
duotonebooleanoffSoft tinted fill on the icon's main body.
fliprtl xoffMirror in right-to-left pages, or always.
animatedfalseanimatedStatic icon that never animates.

Triggers

hover
hold
animated="false"
loop
click me
duotone
flip="x"
html
<tlp-icon name="heart"></tlp-icon>                         <!-- hover (default) -->
<tlp-icon name="trash" trigger="hold"></tlp-icon>          <!-- hover: animate and stay, back on leave -->
<tlp-icon name="bell" animated="false"></tlp-icon>         <!-- static, never animates -->
<tlp-icon name="loader-circle" trigger="loop"></tlp-icon>  <!-- again and again -->
<tlp-icon name="party-popper" trigger="click"></tlp-icon>  <!-- on click -->
<tlp-icon name="anchor" trigger="none"></tlp-icon>         <!-- only el.play() -->

Frameworks

Import the element once at startup, then use <tlp-icon> anywhere. This website is built with Next.js and uses the package exactly like this.

React / Next.js

jsx
'use client';
import 'tlp-icons/element';

export function SaveButton() {
  return (
    <button>
      <tlp-icon name="save" /> Save
    </button>
  );
}

The import is safe during server rendering. TypeScript types for the tag ship with the package (since 0.2.0): add one import and name, trigger and flip are type-checked.

ts
import 'tlp-icons/jsx'; // types <tlp-icon> in JSX (React 18 and 19)

React 18 wrapper

React 18 turns boolean props into strings. Use the tiny optional wrapper instead of the bare tag:

jsx
import { TlpIcon } from 'tlp-icons/react';

<TlpIcon name="heart" size={32} duotone className="like" />

Angular

ts
// main.ts
import 'tlp-icons/element';

// any component
@Component({
  selector: 'app-toolbar',
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  template: `<button><tlp-icon name="bell"></tlp-icon> Alerts</button>`,
})
export class ToolbarComponent {}

Vue / Nuxt

ts
// main.ts
import 'tlp-icons/element';

// vite.config.ts
vue({ template: { compilerOptions: { isCustomElement: tag => tag === 'tlp-icon' } } })
vue
<template>
  <tlp-icon :name="done ? 'circle-check' : 'circle'" />
</template>

Styling

Icons use currentColor, so they take the text color. Theme them with CSS variables:

css
tlp-icon { --tlp-size: 20px; --tlp-stroke: 1.75; }
.danger  { color: #dc2626; }   /* icon color = text color */
.card    { --tlp-duo: .22; }    /* duotone strength */

The hover rule

Hovering an icon animates it. Hovering anything else walks up to the nearest element that holds exactly one icon (a button, a menu item) and animates that one. If it reaches an element with several icons first (a card, a menu, a table row), nothing animates. An animation always plays to the end.

This card has three icons, so hovering its text does nothing

JavaScript API

js
const el = document.querySelector('tlp-icon');
el.play();                         // play once
el.setAttribute('name', 'bell');   // swap the icon

import { icons, categories, getSvg, getIcon } from 'tlp-icons';
getSvg('bell');                                // static SVG markup
getSvg('bell', { size: 32, stroke: 1.5, duotone: true });
getSvg('bell', { animated: true });            // motion baked in
icons.bell;  // { svg, m: [[part, anim, dur, delay, origin?], ...] }

import { config, register } from 'tlp-icons/element';
config.speed = 0.8;   // default 0.6 (about 0.9 s per icon)

Importing icons pulls in the whole set. In pages, prefer <tlp-icon>: it downloads one category at a time.

Animation library

Every choreography is built from these 100 animations. Entrances bring a part into place; gestures move it and return exactly to rest. All keyframes are prefixed tlp- so they never clash with Tailwind or your CSS. Hover a tile:

drawentrance
fillInentrance
popInentrance
fadeInentrance
slideInentrance
riseInentrance
dropInentrance
growentrance
growXentrance
popgesture
breathegesture
jellygesture
swinggesture
wigglegesture
tiltgesture
nodgesture
strikegesture
hopgesture
liftgesture
sinkgesture
nudgegesture
nudgeBackgesture
floatgesture
flipgesture
spinturn
spinBackturn
spinHalfturn
sweepturn
sweepHourturn
blinkgesture
shakegesture
pulseRinggesture
orbitturn
stretchgesture
zoomInentrance
spiralInentrance
swingInentrance
flipInentrance
focusInentrance
bloomentrance
rollInentrance
buzzgesture
tapgesture
pressgesture
beatgesture
flickergesture
twinklegesture
swaygesture
fluttergesture
bobgesture
drivegesture
launchgesture
rollturn
tadagesture
rubbergesture
rattlegesture
springgesture
knockgesture
wavegesture
pendulumgesture
twirlturn
flipYgesture
dripgesture
fallgesture
retracegesture
peekgesture
slideInBackentrance
unfoldentrance
stampInentrance
bounceInentrance
whooshInentrance
elasticInentrance
typeInentrance
drawReverseentrance
slideDownentrance
emergeentrance
jumpgesture
scangesture
scanXgesture
glowgesture
dimgesture
inhalegesture
squeezegesture
pumpgesture
shuttlegesture
dashgesture
recoilgesture
throbgesture
refillgesture
equalizegesture
blipgesture
diggesture
stirgesture
stampgesture
pourgesture
magnifygesture
spinFastturn
windUpturn
tumbleturn
halfBackturn

Accessibility

  • Icons are decorative by default (aria-hidden). When an icon carries meaning, add role="img" and aria-label.
  • With prefers-reduced-motion enabled, icons never animate.
  • Animations are short (0.9 s on average, 1.6 s at most) and always end exactly at rest.

Right-to-left

Motion follows the drawing: an arrow pointing right moves right. On RTL pages, mirror directional icons with flip="rtl"; their motion flips with them.

html
<html dir="rtl">
  <button><tlp-icon name="arrow-right" flip="rtl"></tlp-icon> التالي</button>

Custom choreography

Improve one icon with overrides/<name>.json, or add your own drawing to originals/. Tag moving pieces with p1…p4, the main body with d, then list the steps:

json
{
  "name": "court-hearing",
  "category": "legal",
  "svg": "<path class=\"d p1\" d=\"...\"/><g class=\"p2\">...</g>",
  "motion": [
    { "part": "p1", "anim": "fillIn", "dur": 900, "delay": 0 },
    { "part": "p2", "anim": "strike", "dur": 1200, "delay": 150, "origin": "5px 19px" }
  ]
}

Build from source

bash
git clone https://github.com/Tamer-Mansour/tlp-icons
cd tlp-icons
npm run build      # offline: upstream/ + config/ + overrides/ + originals/ -> dist/
npm test           # offline test suite
npm run sync       # online: latest Lucide + Tabler, then rebuild

cd web && npm install && npm run dev   # this website