Icon
<loomi-icon> — render an icon from the shared @loomidev/icons registry by
name, or any custom SVG via the default slot.
npm install @loomidev/icon litimport "@loomidev/icon";Basic Usage
Section titled “Basic Usage”<loomi-icon name="bell-alert"></loomi-icon><loomi-icon name="check-circle"></loomi-icon><loomi-icon name="trash"></loomi-icon>Icon Sources
Section titled “Icon Sources”source picks which icon set name is looked up in. heroicons is the default.
<loomi-icon name="bell-alert"></loomi-icon><!-- same as source="heroicons" -->
<loomi-icon source="iconsax" name="add"></loomi-icon><loomi-icon source="untitledui" name="user-02"></loomi-icon>heroicons is inlined into @loomidev/icon at build time, so it renders instantly.
iconsax and untitledui are disk-based: the first time a page uses a given icon, it’s
fetched as a real .svg file and cached in memory — every later use of that same icon,
anywhere on the page, is instant. Until that first fetch resolves, <loomi-icon> renders
a correctly-sized empty placeholder, so there’s no layout jump.
Outline, Solid, and Twotone
Section titled “Outline, Solid, and Twotone”variant picks the visual style. Not every source ships every style:
| Source | Available variant values |
|---|---|
heroicons | outline (default), solid |
iconsax | outline (default), solid, twotone |
untitledui | outline (default; the only style it ships) |
Requesting a variant a source doesn’t have (e.g. source="untitledui" variant="solid")
falls back to outline rather than rendering nothing.
<loomi-icon name="bell-alert" variant="outline"></loomi-icon><loomi-icon name="bell-alert" variant="solid"></loomi-icon>
<loomi-icon source="iconsax" name="add" variant="outline"></loomi-icon><loomi-icon source="iconsax" name="add" variant="solid"></loomi-icon><loomi-icon source="iconsax" name="add" variant="twotone"></loomi-icon>Icons From a Directory
Section titled “Icons From a Directory”Use directory when your project has custom icon files. The name becomes the file
name. If name has no extension, .svg is used.
directory is not resolved relative to the component package or the JavaScript module.
It is written directly into the rendered <img src="...">, so the browser resolves it
the same way it resolves any normal image URL in your page:
directory="assets/images"is relative to the current page URL.directory="/assets/images"is root-relative to your site or app domain.directory="https://cdn.example.com/icons"is an absolute external URL.
<loomi-icon name="airpods" directory="assets/images"></loomi-icon><!-- renders assets/images/airpods.svg -->
<loomi-icon name="airpods" directory="/assets/images"></loomi-icon><!-- renders /assets/images/airpods.svg -->
<loomi-icon name="airpods.png" directory="assets/images"></loomi-icon><!-- renders assets/images/airpods.png -->Sizing
Section titled “Sizing”Icons default to 1.5rem. Set size to any CSS length — it’s applied via the
--loomi-icon-size custom property, so you could also override that variable directly
from your own CSS if you’d rather size a whole group of icons at once.
<loomi-icon name="star" size="1rem"></loomi-icon><loomi-icon name="star" size="2rem"></loomi-icon><loomi-icon name="star" size="3rem"></loomi-icon>Coloring
Section titled “Coloring”There’s no color attribute — icons render with currentColor, so they
inherit the text color of whatever they’re placed in. Set color (or class) on the
icon itself, or on a parent, like any other inline element.
<loomi-icon name="bell-alert" style="color:#dc2626"></loomi-icon><span style="color:#16a34a"> <loomi-icon name="check-circle"></loomi-icon> Saved</span>This doesn’t apply to branded badges (below) — those always use the theme’s primary
color, not the inherited/inline color.
Branded Badges
Section titled “Branded Badges”Set branded to sit the icon on a rounded, primary-colored background instead of
rendering it bare — a common “featured icon” treatment for empty states, onboarding
steps, or notification list items.
<loomi-icon source="iconsax" name="gift" variant="solid" branded shade="dark"></loomi-icon><loomi-icon source="untitledui" name="file-02" branded shade="light"></loomi-icon>| Attribute | Default | Description |
|---|---|---|
branded | false | Renders the icon on a background badge instead of bare. |
shade | light | light (soft primary tint behind a darker primary icon) | dark (solid primary fill behind a white icon). Only applies when branded. |
radius | medium | Badge corner rounding: none | small | medium | full. Only applies when branded. |
The badge always uses the theme’s primary color (the same --loomi-primary-* slots
every other component reads), so a single :root { --loomi-primary-600: ...; } override
re-skins every branded icon on the page along with everything else. Padding and the icon
itself both scale with size/--loomi-icon-size, so a bigger badge stays proportional.
Accessible Labels
Section titled “Accessible Labels”By default an icon is purely decorative (aria-hidden="true") — appropriate when it
sits next to visible text (as in a button or tab heading). If the icon is the only
content conveying meaning (e.g. an icon-only button), set label so screen readers
announce it.
<loomi-icon name="trash" label="Delete"></loomi-icon>Custom SVG
Section titled “Custom SVG”Don’t have a registered icon for what you need? Drop any raw <svg> into the default
slot instead of setting name — it’s sized and colored the same way (set its stroke
to currentColor and it’ll inherit color the same as a registry icon).
<loomi-icon size="2rem"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"> <path d="M12 2l2 7h7l-5.5 4 2 7-5.5-4-5.5 4 2-7L2 9h7z" /> </svg></loomi-icon>Registering Custom Icons
Section titled “Registering Custom Icons”For an icon you’ll reuse across your app, register it once with the shared registry
instead of repeating raw SVG markup everywhere — it then becomes usable via name from
any component that renders icons (<loomi-icon>, <loomi-button icon="...">,
<loomi-tab icon="...">, <loomi-alert icon="...">, and more):
import { registerLoomiIcon } from "@loomidev/icons";import { svg } from "lit";
registerLoomiIcon("rocket", svg`<path d="…" />`);<loomi-icon name="rocket"></loomi-icon>Accessibility
Section titled “Accessibility”For the library-wide baseline, see Foundations — Accessibility.
Responsive behavior
Section titled “Responsive behavior”For the shared container and viewport rules, see Foundations — Responsive behavior.
Dark mode
Section titled “Dark mode”For theme activation, token overrides, and contrast guidance, see Foundations — Dark mode.
Attributes
Section titled “Attributes”| Attribute | Default | Description |
|---|---|---|
name | (blank) | Registered icon name (see @loomidev/icons). |
source | heroicons | Icon set. heroicons | iconsax | untitledui. Ignored when directory is set. |
variant | outline | Visual style. outline | solid | twotone — availability depends on source (see Outline, Solid, and Twotone). Ignored when directory is set. |
directory | (blank) | Directory URL for file-based icons. Written directly to <img src>, so relative paths resolve from the current page URL; .svg is added when name has no extension. |
size | (blank) | CSS size, e.g. 1.5rem, 32px. Sets --loomi-icon-size. |
stroke-width | 1.5 | Stroke width. Heroicons outline only — iconsax and untitledui ship a fixed weight per icon. |
label | (blank) | Accessible label; when omitted the icon is aria-hidden. |
branded | false | Renders the icon on a primary-colored background badge (see Branded Badges). |
shade | light | Badge background: light | dark. Only applies when branded. |
radius | medium | Badge corner radius: none | small | medium | full. Only applies when branded. |
| Slot | Description |
|---|---|
| (default) | Content placed inside the component. |
Full Example
Section titled “Full Example”<loomi-icon name="bell-alert" variant="solid" size="2rem" label="Notifications" style="color:#7c3aed"></loomi-icon>
<loomi-icon source="iconsax" name="notification" variant="twotone" size="2rem" label="Notifications" style="color:#7c3aed"></loomi-icon>Framework integration
Section titled “Framework integration”<loomi-icon> is a standard custom element, so the browser can use it in plain HTML, Blade, React, Vue, Angular, Svelte, Astro, and most other frameworks. The important beginner rule is: install the package, import it once before the tag is rendered, then write the Loomi tag in your template.
Where to run commands
Section titled “Where to run commands”Run install commands from the app where you want to use this component. That means the folder that contains that app’s package.json. Do not run these install commands from packages/icon unless you are editing LoomiUI itself.
cd /path/to/your-appnpm install @loomidev/icon litIf you are contributing to LoomiUI itself, first move to the top-level components folder. That is where the main package.json for all packages lives, and pnpm --filter ... commands should be run from there:
cd /path/to/your-copy-of-loomiui/componentspnpm --filter @loomidev/icon buildpnpm --filter @loomidev/icon typecheckChoose your framework
Section titled “Choose your framework”Use the CDN version for prototypes, documentation pages, or a quick reproduction. The import map tells the browser where to find Lit, which Loomi components use internally.
<script type="importmap"> { "imports": { "lit": "https://esm.sh/lit@3.3.3", "lit/": "https://esm.sh/lit@3.3.3/" } }</script><script type="module" src="https://esm.sh/@loomidev/icon"></script>
<loomi-icon name="bell-alert" variant="outline" size="1.5rem" label="Notifications"></loomi-icon>In Vite, Webpack, Parcel, Rollup, or a framework build pipeline, install the package and import it once in your main app JavaScript file. After that, you can use the Loomi tag anywhere in your app.
import "@loomidev/icon";Run the install command from your Laravel project root, then import the component in resources/js/app.js. If your project uses Laravel Vite, npm run dev and npm run build should also be run from the Laravel project root.
cd /path/to/your-laravel-appnpm install @loomidev/icon litnpm run devimport "@loomidev/icon";<loomi-icon name="bell-alert" variant="outline" size="1.5rem" label="Notifications"></loomi-icon>React can render Loomi tags directly. If you are on React 18, or if you need to pass arrays, objects, or functions, use a ref and assign those values after the component mounts.
import "@loomidev/icon";
export function LoomiExample() { return ( <loomi-icon name="bell-alert" variant="outline" size="1.5rem" label="Notifications"></loomi-icon> );}If TypeScript does not recognize the Loomi tag in JSX, add it to your app’s JSX type declarations.
Import the package in the component that uses it, or once in your main Vue file. Vue templates can use Loomi tags directly. For arrays, objects, or functions, pass the value as a JavaScript property instead of as plain text.
<script setup>import "@loomidev/icon";</script>
<template> <loomi-icon name="bell-alert" variant="outline" size="1.5rem" label="Notifications"></loomi-icon></template>If Vue warns that the tag is an unknown component, configure compilerOptions.isCustomElement for tags that start with loomi- in your Vite or Vue config.
Import the package once and tell Angular to allow custom HTML tags with CUSTOM_ELEMENTS_SCHEMA. For NgModule apps, add the schema to the module instead of the standalone component.
import { CUSTOM_ELEMENTS_SCHEMA, Component } from "@angular/core";import "@loomidev/icon";
@Component({ selector: "app-root", standalone: true, schemas: [CUSTOM_ELEMENTS_SCHEMA], template: ` <loomi-icon name="bell-alert" variant="outline" size="1.5rem" label="Notifications"></loomi-icon> `,})export class AppComponent {}Svelte can import the package inside a component script. Astro can import it in the frontmatter of the page or layout where the tag appears.
<script> import "@loomidev/icon";</script>
<loomi-icon name="bell-alert" variant="outline" size="1.5rem" label="Notifications"></loomi-icon>---import "@loomidev/icon";---
<loomi-icon name="bell-alert" variant="outline" size="1.5rem" label="Notifications"></loomi-icon>Server-side rendering notes
Section titled “Server-side rendering notes”Frameworks such as Next.js, Nuxt, SvelteKit, and Astro sometimes render HTML on the server before browser-only code runs. If your framework complains, move the Loomi import to client-side code. In Next.js, that usually means a component with "use client"; in Nuxt, it often means a .client.ts plugin.
Dependencies
Section titled “Dependencies”@loomidev/core@loomidev/icons