HyIcon
Usage examples on this page are written for Lit / plain HTML (
<hy-icon>). The same component ships asHyIconin@whitespaceux/harmony-react(native React 19), with typed wrappers for Angular, Solid, Svelte, and Vue. The API reference below applies to all frameworks.
A flexible, SSR-safe icon component that renders SVG icons from registered icon sets.
Icon Sets
All icons are opt-in via @whitespaceux/harmony-icons. Three import levels per library:
- System —
import '@whitespaceux/harmony-icons/mdi/system'— the 47 icons components draw internally - Full —
import '@whitespaceux/harmony-icons/mdi'— the whole library (about 1,000 Material / 900 Lucide / 590 Bootstrap names; each barrel's header states its count) - Individual —
import '@whitespaceux/harmony-icons/mdi/home'— one icon
Available libraries: mdi (Material Design Icons), lucide, bi (Bootstrap Icons). 323 names exist in all three (@whitespaceux/harmony-icons/common-names); markup that sticks to them survives a library switch — swap libraries by changing the import path. A name outside that set renders only in the libraries that have it.
Theming
An icon paints --hy-icon-color, else the color of the text around it (currentColor). Parent components set --hy-icon-color on their :host, so a slotted icon takes the component's ink in every role, emphasis and state; a bare icon in a page's own text follows that text, a Pages ink included. Set --hy-icon-color (or variant) only for an icon whose color differs from its text.
Important: --hy-icon-color must be set on :host, not on .base or shadow DOM elements. Slotted icons live in light DOM and only inherit custom properties from the host.
For the common case "this icon means danger/warning/success/…", use the variant property instead of writing --hy-icon-color by hand. variant writes the matching semantic foreground token into --hy-icon-color on the host; an externally-set --hy-icon-color (inline, class, or parent-component cascade with higher specificity) still wins.
Color contract for registered SVGs. A fill / stroke attribute is monochrome ink: the component repaints it to currentColor at render time (on the root <svg> and on every descendant), so a raw export with a baked fill="#1A73E8" follows the theme, --hy-icon-color, variant and forced-colors like any stock icon. none / transparent are respected and fills inside <mask> are left alone. A stroke icon without its own stroke-width renders at SVG's default 1px. An inline style="fill: …" is fixed artwork and is never touched — that is the opt-out for a brand mark.
Sizes
size scales the icon against the surrounding font size (the icon is 1em square), so the pixels depend on the parent. Components size their own icons from the --hy-icon-size-* ladder instead.
| Size | Scale | At a 16px font | Use case |
|---|---|---|---|
sm | 0.625em | 10px | Badges, dense layouts |
md | 1em | 16px | Standard (default) |
lg | 1.25em | 20px | Buttons, UI elements |
xl | 1.5em | 24px | Headers |
2xl | 2em | 32px | Hero sections |
Accessibility: built in
Unlabeled icons are decorative by default: without a label, the icon is hidden from screen readers (the raw icon name is never announced). An icon with a label is exposed as role="img" with that name.
Accessibility: your part
- Give a standalone icon that carries meaning a
labelthat says what it means, not the glyph's name. - If people need the
tooltipto understand the icon, show a visible text label instead. - Pair a status-colored icon (
danger,warning,success) with text that says what happened. Color alone carries no meaning.
When to use
- A symbol beside text that helps people scan: in a list, a status, a heading.
- A status shown with its color, with
variant.
Do
- Use one icon for one meaning across the product.
- Size it with the text it sits beside.
When not to use
- An icon people click to act:
hy-icon-button. - The product's logo: an
<img>of the brand's artwork, the file made for the surface's color mode. - A concept with no widely understood glyph: a visible text label, with the icon at most beside it.
Examples
Basic usage (decorative — hidden from screen readers)
<hy-icon name="close"></hy-icon>With size and accessibility
<hy-icon name="close" size="lg" label="Close dialog" tooltip="Close this dialog"> </hy-icon>Decorative icon (hidden from screen readers)
<hy-icon name="check" decorative></hy-icon>Semantic color variant
<hy-icon name="alert-circle-outline" variant="danger"></hy-icon>
<hy-icon name="check" variant="success"></hy-icon>API
Properties
| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
name | name | string | '' | The name of the icon to display. Must exist in the selected icon set. |
set | set | IconSetName | undefined | undefined | Per-instance icon set override. When unset, the icon resolves its set from the inherited --hy-icon-set CSS custom property (which cascades across shadow boundaries), then falls back to the global HyIcon.defaultSet. |
size | size | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'md' | Predefined size, relative to the surrounding font size (px at a 16px font). |
variant | variant | 'neutral' | 'brand' | 'success' | 'warning' | 'danger' | 'info' | 'subtle' | 'inverse' | 'neutral' | Semantic color variant. neutral (default) keeps the inherited cascade so parent components (button, chip, list, etc.) that set --hy-icon-color still drive the color. Any other value writes the matching --hy-foreground-*-rest token into --hy-icon-color on this host, which consumers can still override externally (inline style, class, or higher-specificity cascade). |
label | label | string | undefined | — | Accessible label for the icon. When set, the icon is exposed to screen readers as an image with this name. When omitted, the icon is treated as decorative (hidden from screen readers) — the raw registry name is never announced. Ignored when decorative is true. |
decorative | decorative | boolean | false | Explicitly marks the icon as purely decorative, hiding it from screen readers (aria-hidden="true", no role="img"). Unlabeled icons are already treated as decorative; set this to make the intent explicit, or to suppress a label that only sighted users should get via tooltip. |
tooltip | tooltip | string | undefined | — | Tooltip text shown on hover for additional context. |
CSS Parts
| Part | Description |
|---|---|
base | The wrapper <span> around the SVG content. |
error | Applied alongside base when the icon fails to resolve (invalid name). |
CSS Custom Properties
The documented hooks. Every override hook the component reads — one per token it paints — is listed in @whitespaceux/harmony/theme-api.json, and @whitespaceux/harmony/component-bindings.json (the Harmony MCP get-bindings tool) says which part and state each one paints.
| Property | Default | Description |
|---|---|---|
--hy-icon-color | currentcolor | Override icon color from parent components. Set on :host, not .base. Falls back to the color of the text around the icon (currentColor). Reaches every fill / stroke attribute in the SVG, which the component repaints to currentColor (none respected; an inline style is the opt-out). |
--hy-icon-set | — | Override the active icon library for a subtree (cascades across shadow boundaries). Resolution: set prop, then this property, then HyIcon.defaultSet. One portable name resolves to the chosen library's glyph. |
--hy-icon-error-opacity | — | Opacity of the missing-icon placeholder (0.45 unless set) |
Methods
registerSet()
Register a complete icon set. Icons are SVG strings keyed by name.
Parameters:
name- The name for this icon seticons- A flat map of icon name to SVG string
registerIcon()
Register a single icon into an existing (or new) set.
Parameters:
set- The icon set namename- The icon namesvg- The SVG string
hasIcon()
Check if an icon exists in a set.
Parameters:
set- The icon set namename- The icon name