---
outline: deep
---

# Icon

Renders icons from any Iconify icon set. Icons are loaded on demand from the Iconify CDN. By default all icons are scaled to `1em` height — use `font-size` to control icon size.

**`<l-icon>`** — Custom Element · Shadow DOM

>
> `l-icon` uses [Iconify](https://iconify.design/) under the hood. Browse all available icons at [icon-sets.iconify.design](https://icon-sets.iconify.design/).

## Options

```html
<l-icon
  name="lucide:home"
  class="text-4xl"
></l-icon>
```

### Sizes

Icons scale with `font-size`. Use Tailwind `text-*` classes.

```html
<div class="flex items-center gap-4">
  <l-icon
    name="lucide:home"
    class="text-sm"
  ></l-icon>
  <!-- 14px -->
  <l-icon
    name="lucide:home"
    class="text-xl"
  ></l-icon>
  <!-- 20px -->
  <l-icon
    name="lucide:home"
    class="text-3xl"
  ></l-icon>
  <!-- 30px -->
  <l-icon
    name="lucide:home"
    class="text-5xl"
  ></l-icon>
  <!-- 48px -->
</div>
```

### Icon sets

Use any icon from the Iconify library with the `prefix:name` format.

```html
<div class="flex items-center gap-4 text-2xl">
  <l-icon name="lucide:heart"></l-icon>
  <l-icon name="mdi:home"></l-icon>
  <l-icon name="tabler:star"></l-icon>
  <l-icon name="ph:lightning-bold"></l-icon>
</div>
```

### Your own icon set

Icons outside the Iconify CDN — a house collection generated from your own SVGs — must be registered first. On npm, use the `addCollection()` **this package re-exports**; on the CDN build, assign `window.IconifyPreload` before the script tag.

```js
import { addCollection } from 'luxen-ui/icon';
import acmeIcons from './icons/acme.json'; // { prefix: 'acme', icons: { … } }

addCollection(acmeIcons);
```

```html
<script>
  // Read when the module loads, so it has to come first.
  window.IconifyPreload = [{ prefix: 'acme', icons: {} }];
</script>
<script
  type="module"
  src="https://cdn.jsdelivr.net/npm/luxen-ui/cdn/elements/icon/index.js"
></script>
```

```html
<l-icon name="acme:location"></l-icon>
```

Two rules, because both fail silently:

- **This `addCollection`, not a framework binding's.** Icon storage belongs to the `iconify-icon` module and every copy of it has its own, so a collection registered through `@iconify/vue` or `@iconify/react` is invisible here — the icon renders nothing, at zero width, with no error.
- **Before the first icon mounts.** Registering writes to storage; it does not re-render icons already on the page.

`addIcon()` and `setCustomIconLoader()` are re-exported the same way. A name that resolves to nothing logs one warning per name.

### Accessible icons

Icons are decorative by default (`aria-hidden="true"`). Add `label` for meaningful icons.

```html
<l-icon
  name="lucide:alert-triangle"
  label="Warning"
  class="text-2xl text-amber-500"
></l-icon>
```

## Accessibility

### Criteria

- **Decorative icons** — Icons are hidden from assistive technology by default via `aria-hidden="true"`
- **Meaningful icons** — Set `label` to convey meaning — adds `aria-label` and removes `aria-hidden`

### Rules

- Always add `label` when the icon is the only content conveying meaning (e.g., icon-only buttons)
- Omit `label` when the icon is next to visible text that already conveys the same meaning

## API reference

### Importing

```js
import 'luxen-ui/icon';
```

### Attributes & Properties

- **name**: `string` — The icon name in Iconify format (e.g. `mdi:home`, `lucide:check`).
- **label**: `string | undefined` — Accessible label. When set, the icon becomes meaningful (`role="img"` + `aria-label`). When absent, the icon is decorative.

### CSS custom properties

- `--color` (default: `currentColor`) — The color of the icon.
