Skip to content

Icon <l-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.

HTML tag<l-icon>
Native
Progressive
Plain
Shadow-DOM
Shadow-DOM Custom Element

INFO

l-icon uses Iconify under the hood. Browse all available icons at icon-sets.iconify.design.

Options

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

Sizes

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

Code
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.

Code
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.

Code
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"

WCAG1.1.1
RGAA1.1
Meaningful icons

Set label to convey meaning — adds aria-label and removes aria-hidden

WCAG1.1.1
RGAA1.1

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

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

CSS custom properties

--colordefault:currentColorCustom property
The color of the icon.