<Icon name="…"> is the component layer over the framework's icons. It resolves a
name to markup through a small, swappable provider system, so a project renders icons
with whatever set(s) it already uses (Font Awesome, inline-SVG Lucide/Tabler, …) without hand-authoring
elements at each call-site. The raw masked glyph primitive it builds on is catalogued on Design › Icons.
How a name resolves
<Icon> resolves a name in two stages (see resolveIcon in icon/icon-provider.ts):
- Framework affordance first — built-in & reserved. If the name is one of the
closed set of masked structural affordances (
success,chevron-down,close/x, …) it emits<span class="pa-icon pa-icon--NAME">and stops. No provider can shadow an affordance, so the framework's own glyphs always render zero-config. - Provider list. Otherwise the name is handed to each provider configured on
PureAdminProvider, in order — the first to return non-empty markup wins. - Nothing. If no provider matches,
<Icon>renders nothing (handy for data-driven names that may be absent).
"fa close", "tabler star") so they don't collide
with the reserved bare affordance names — a bare "close" always resolves to the
framework glyph.1. Affordances — built-in, reserved
Zero config. These resolve to the masked primitive before any provider is consulted, so <Icon> works out of the box for the framework's structural glyphs.
successdangerwarninginfosearchcheckchevron-down<Icon name="success" /> <Icon name="chevron-down" />
2. Providers — your icon set(s)
Anything that isn't an affordance goes to the provider list. This docs app configures a single
inline-SVG provider (svgIcons(navIcons)), so the nav glyphs below are real <Icon name="…"> calls routed through it:
dashboardcolorscardstablekpimoviesBuilt-in providers
Each is a factory returning a provider; compose them in an ordered list. You do not add masked() — affordances are built-in.
fontAwesome(opts?)—name="user"→<i class="fa-solid fa-user fa-fw">.svgIcons(map, opts?)— inline<svg>from a{ name: innerMarkup }map (Lucide, Tabler, Heroicons-outline, …).combine(...providers)— fold several into one reusable provider (the list already composes; this is for pre-building a single provider).masked()— emits apa-icon--NAMEspan for an affordance name; rarely needed now that affordances are built-in, kept for advanced composition.
Configure them
<script>
import {
PureAdminProvider,
svgIcons,
fontAwesome,
combine
} from '@keenmate/svelte-pure-admin';
import { lucidePaths } from '$lib/icons'; // { dashboard: '<path …/>', … }
</script>
<!-- Ordered list: first provider to return markup wins. Framework
affordances resolve BEFORE the list, so you never add masked() here. -->
<PureAdminProvider iconProviders={[svgIcons(lucidePaths), fontAwesome()]}>
{@render children()}
</PureAdminProvider> Write your own
A provider is a pure (name, ctx) => string — return markup, or '' to pass
the name to the next provider. The full render context (class, size, isInteractive, label) flows to every provider so a set can embed its own
sizing and hover marker. Parsing a "set name" convention is the provider's job — <Icon> just calls the callbacks in order.
import type { IconProvider } from '@keenmate/svelte-pure-admin';
// A provider is (name, ctx) => markup string, or '' to pass the name on.
// The name is opaque — the provider parses whatever convention you type.
const tabler: IconProvider = (name, ctx) => {
const [set, icon] = name.split(' ');
if (set !== 'tabler') return ''; // not ours → pass
return `<svg class="${ctx.isInteractive ? 'pc-icon-hover-highlight' : ''}"
width="1em" height="1em" viewBox="0 0 24 24">${paths[icon]}</svg>`;
};
// <Icon name="tabler star" /> → this provider
// <Icon name="success" /> → framework affordance (never reaches providers)Size, accessibility & hover
size— a CSS length; setsfont-size+--pa-icon-sizeon the host.label— when set, the icon is exposed asrole="img"with that name; otherwise it'saria-hidden.isInteractive— adds.pc-icon-hoverso a standalone icon becomes its own hover affordance. Inside a.pa-btn/ nav link / tab the control is already the hover context, so you don't need it there. The provider embeds its set's hover marker (pc-icon-hover-fillfor Font Awesome,pc-icon-hover-highlightfor outline SVG,--pa-icon-src-hoverfor masked).
<Icon name="success" /> <!-- affordance → <span class="pa-icon pa-icon--success"> --> <Icon name="dashboard" /> <!-- provider (svgIcons) → inline Lucide <svg> --> <Icon name="fa delete" /> <!-- provider (your parser) → Font Awesome --> <Icon name="nope" /> <!-- no match → renders nothing --> <Icon name="settings" size="2rem" isInteractive label="Open settings" />
<Icon> vs a raw .pa-icon span
Use <Icon name>
- The name is data/config-driven and you don't know its type ahead of time.
- You want one call-site that works across your configured icon sets.
- You need the provider's hover marker / size / a11y wiring for free.
Use a raw .pa-icon span
- You're writing a fixed framework affordance inline (close button, chevron).
- It's how the library's own components render affordances — no provider dependency.
- See Design › Icons for the full glyph gallery + token chain.
<Icon name="success"> and <span class="pa-icon pa-icon--success"> are interchangeable. <Icon> adds the provider seam for everything else.