Icon
Icon renders a single glyph, loaded by name, in any size or color. It works well on its own, or gets composed automatically inside other components that expose their own icon option.
When to use
Use an icon on its own for a standalone visual cue, such as a status marker, a decorative flourish next to a heading, or an inline glyph. When it lives inside another component that already offers its own icon option, such as a button or a tab, set that option instead of composing an icon by hand, since it keeps sizing and spacing consistent for free.
Install & usage
Pick a framework in the toolbar above and these snippets adapt.
npm install @eunomia/elements
import "@eunomia/elements/icon.js";
<eun-icon name="favorite"></eun-icon>
Importing the file registers <eun-icon> as a custom element, with
no further setup needed. It works with any framework, or none, since
it's a standard web component.
npm install @eunomia/elements
<script type="module">
import "@eunomia/elements/icon.js";
</script>
<eun-icon name="favorite"></eun-icon>
npm install @eunomia/elements
import "@eunomia/elements/icon.js";
function Favorite() {
return <eun-icon name="favorite"></eun-icon>;
}
npm install @eunomia/elements
"use client";
import "@eunomia/elements/icon.js";
export function Favorite() {
return <eun-icon name="favorite"></eun-icon>;
}
npm install @eunomia/elements
<script setup>
import "@eunomia/elements/icon.js";
</script>
<template>
<eun-icon name="favorite"></eun-icon>
</template>
npm install @eunomia/elements
import { CUSTOM_ELEMENTS_SCHEMA, Component } from "@angular/core";
import "@eunomia/elements/icon.js";
@Component({
selector: "app-favorite",
template: `<eun-icon name="favorite"></eun-icon>`,
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class FavoriteComponent {}
Loading
Icons ship inside the package's JavaScript, so they work with any bundler (Vite, webpack, Turbopack, the Angular CLI) and from a CDN, with nothing to copy into your public folder. Each icon is loaded the first time it renders, together with a few dozen others stored alongside it, and later renders read it from memory.
setIconBaseUrl is no longer needed. It is kept so existing calls still
compile, and does nothing.
Guidance
- Use
eun-icondirectly for a standalone glyph: a status marker, a decorative flourish, an inline visual cue - Prefer a component's own
iconproperty (eun-button,eun-tab, ...) over composingeun-iconby hand inside it, when that property exists - Browse the full set on the
Icons page and copy the exact name from there - Pick a shape that matches the surrounding state (e.g. an
outlineglyph for an empty/inactive state, the filled default for an active one)
- Relying on an icon's color or shape alone to convey meaning, with no accompanying text
- Using an icon-only interactive element without an
aria-labelon that parent element - Assuming every icon ships all four shapes: an icon missing a given shape automatically falls back to its default (filled) glyph instead of disappearing, but that fallback still changes what's rendered
Live testing
Properties
Attributes
| Name | Type | Default | Description |
|---|---|---|---|
| name | EunomiaIconName | — | The icon to render. A shape variant baked into the name is used when shape isn't set |
| shape | EunomiaIconType | — | Forces a shape variant, taking priority over any variant already baked into name |
| size | string | — | The icon size, in any valid CSS unit. A bare number is treated as pixels |
Import the exact TypeScript type behind any property above, see
CSS custom properties
| Name | Description |
|---|---|
| --icon-size | Sets the size of the icon, overridden by the size property when set |
| --icon-color | Sets the color of the icon, defaulting to the surrounding text color |
| --icon-background | Sets a background color behind the icon, for example for a hover highlight. Transparent by default |
| --icon-padding | Sets the space between the icon and its background box. Zero by default |
| --icon-padding-block | Sets the vertical padding, as one length applied to both sides. Ignored when --icon-padding is set |
| --icon-padding-inline | Sets the horizontal padding, as one length applied to both sides. Ignored when --icon-padding is set |
| --icon-border-radius | Sets the corner radius of the background box |
| --icon-border-width | Sets the border width of the background box. Zero by default |
| --icon-border-color | Sets the border color of the background box, once --icon-border-width is set |
| --icon-transition | Sets the transition applied to the icon's color, background, and size changes. 0.2s by default |
CSS shadow parts
| Name | Description |
|---|---|
| wrapper | The background box around the icon, for effects its CSS custom properties don't cover |
Variants
Shapes
Every icon is available in up to four shapes: default (filled),
outline, round, and sharp. Set it via the shape property.
Not every icon ships all four, so one that's missing a given shape
falls back to its default glyph automatically.
<eun-icon name="add_location"></eun-icon>
<eun-icon name="add_location" shape="outline"></eun-icon>
<eun-icon name="add_location" shape="round"></eun-icon>
<eun-icon name="add_location" shape="sharp"></eun-icon>
Shape baked into the name
As a shorthand, name can carry its own shape suffix (e.g.
add_location_outline) instead of setting shape separately, handy when
copying a name straight from the
shape property always wins.
<eun-icon name="add_location_outline"></eun-icon>
<!-- shape="round" overrides the "_outline" suffix baked into name -->
<eun-icon name="add_location_outline" shape="round"></eun-icon>
Sizes
Set any CSS size unit via the size property, or --icon-size for a
CSS-only override. A bare number is treated as pixels, while a % value
is converted to rem.
<eun-icon name="favorite" size="16"></eun-icon>
<eun-icon name="favorite" size="24"></eun-icon>
<eun-icon name="favorite" size="32"></eun-icon>
<eun-icon name="favorite" size="48"></eun-icon>
Part of the
Color
By default (no --icon-color set), an icon inherits the surrounding
text color, handy for an icon embedded inline in a link or a piece of
text.
<div style="color: #148cd2;">
<eun-icon name="favorite"></eun-icon>
</div>
Override it with --icon-color:
<eun-icon name="favorite" style="--icon-color: #dc1414;"></eun-icon>
Background
Give the icon a background box with --icon-background, combine it
with --icon-padding (zero by default, so the background hugs the
icon exactly) to add breathing room around it, and
--icon-border-radius to shape the corners. Both the color and
background transition smoothly, so this is typically wired to
:hover to build an icon-picker-style highlight. Hover the icon
below:
eun-icon {
--icon-color: var(--eun-color-grey-600);
--icon-padding: 8px;
}
eun-icon:hover {
--icon-color: var(--eun-color-primary-500);
--icon-background: var(--eun-color-primary-alpha-20);
}
Outline the box with --icon-border-width, zero by default, and
--icon-border-color, which defaults to the theme's border color:
<eun-icon
name="calendar_today"
style="--icon-padding: 8px; --icon-background: var(--eun-surface-sunken); --icon-border-width: 1px;"
></eun-icon>
Composed into other components
Most interactive components that accept an icon render eun-icon
internally through their own icon property or slot, rather than
requiring it to be composed by hand:
<!-- eun-button: icon slotted at start or end -->
<eun-button>
Delete
<eun-icon slot="start" name="delete"></eun-icon>
</eun-button>
<!-- eun-tab: icon set directly as an attribute -->
<eun-tab slot="navigation" panel="inbox" icon="mail">Inbox</eun-tab>
See
Full icon set
Every icon this component can render, browsable by name and shape,
with click-to-copy markup: see
Server-side rendering
An icon stays empty until the element upgrades and loads its SVG, then
pushes the text around it aside. Link icon-ssr.css in the page's
<head> to reserve its box from the first paint:
<link
rel="stylesheet"
href="node_modules/@eunomia/elements/dist/ssr/icon-ssr.css"
/>
A bundler that resolves package exports can reach it as
@eunomia/elements/icon-ssr.css.
It reads size, --icon-size and the padding and border properties.
size takes a number of pixels or any CSS length, which only a browser
supporting typed attr() reads in full. Elsewhere, whole pixel sizes from
8 to 64 are covered.
Custom colors
The custom properties that change colors, borders, shadows and corners, at a glance. The API tab lists every property of the component.
| Variable | Sets |
|---|---|
--icon-color |
Sets the color of the icon, defaulting to the surrounding text color |
--icon-background |
Sets a background color behind the icon, for example for a hover highlight. Transparent by default |
--icon-border-radius |
Sets the corner radius of the background box |
--icon-border-width |
Sets the border width of the background box. Zero by default |
--icon-border-color |
Sets the border color of the background box, once --icon-border-width is set |
Keyboard interactions
None: the icon isn't focusable or interactive on its own, so there's nothing to reach with the keyboard.
Semantics and screen readers
Decorative by default
The rendered SVG always carries aria-hidden="true": eun-icon is
treated as purely decorative and is never exposed to assistive
technology, even when used alone with no other visible content.
Icon-only interactive elements
When an icon is the only content of an interactive element (an
icon-only button, for instance), set an aria-label on that parent
element yourself, describing the action, not the icon.
eun-icon cannot provide one on its own behalf: since its SVG is
aria-hidden, a screen reader would otherwise announce nothing at
all for that control. See the Icon-only example on the
Visual and motion
Color contrast
When an icon conveys meaning on its own rather than being purely
ornamental (a status marker, a severity indicator in a table row,
...), its color against its background must still meet the
Reduced motion
The color and background transition used for hover/focus highlights
(see the Background example) respects
prefers-reduced-motion: reduce: with that OS-level setting on, the
change applies instantly instead of fading.
Direction (RTL)
eun-icon never auto-mirrors a glyph for right-to-left layouts.
For a directional icon (an arrow, a "next"/"previous" chevron, ...),
either pick an icon name whose meaning doesn't depend on direction,
or apply your own transform: scaleX(-1); in an RTL context.
Reference links
RGAA 4.1.2 MDN: aria-hidden WCAG 1.4.11: Non-text Contrast