Skip to content

@absoluteui/icons

Icon registry and the built-in icon set.

import { ... } from '@absoluteui/icons';

Components ask for icons by name. This package resolves those names, lets you add or replace icons (including whole third-party libraries such as Lucide, Font Awesome, and Material Symbols), sizes and layers them, and renders them as accessible elements. The Icons guide covers every option in depth.

How do I show an icon in my own markup, at a given size?

Section titled “How do I show an icon in my own markup, at a given size?”

renderIcon returns the element components use: decorative by default, an image with an accessible name when you pass label. size takes a theme size ('xs' 0.75rem, 'sm' 1rem, 'md' 1.25rem, 'lg' 1.5rem, 'xl' 2rem) or a CSS length.

import { renderIcon } from '@absoluteui/icons';
const decorative = renderIcon('check', { size: 'lg' });
decorative.getAttribute('aria-hidden'); // => 'true'
decorative instanceof SVGElement ? decorative.style.fontSize : ''; // => 'var(--aui-icon-size-lg, 1.5rem)'
const meaningful = renderIcon('check-circle', { label: 'Approved', size: '20px' });
[meaningful.getAttribute('role'), meaningful.getAttribute('aria-label')]; // => ['img', 'Approved']

How do I resize the icons of a component, a region, or the whole app?

Section titled “How do I resize the icons of a component, a region, or the whole app?”

Set --aui-icon-size on the component or any ancestor: every icon inside follows it (component icons, and those from renderIcon). To change the defaults everywhere, override the theme tokens --aui-icon-size-xs … --aui-icon-size-xl.

import { renderIcon } from '@absoluteui/icons';
const toolbar = document.createElement('div');
toolbar.style.setProperty('--aui-icon-size', '1.5rem'); // this region only
document.documentElement.style.setProperty('--aui-icon-size-sm', '1.125rem'); // app-wide default for small icons
toolbar.append(renderIcon('search'));

Install @fortawesome/free-solid-svg-icons (or another Font Awesome SVG package) and convert the icons you use with fromFontAwesome. Only the imported icons are in your bundle. Font Awesome Free icons are licensed CC BY 4.0: keep its attribution.

import { faCalendarDays, faUser } from '@fortawesome/free-solid-svg-icons';
import { fromFontAwesome, registerIcons, renderIcon } from '@absoluteui/icons';
registerIcons({ user: fromFontAwesome(faUser), calendar: fromFontAwesome(faCalendarDays) });
renderIcon('user').getAttribute('viewBox'); // => '0 0 448 512'

If you use Font Awesome’s web font instead, map names to its classes: { kind: 'class', className: 'fa-solid fa-user' }, and load its stylesheet yourself.

How do I use Material Symbols from Google Fonts?

Section titled “How do I use Material Symbols from Google Fonts?”

Load the font stylesheet from Google Fonts, allow its hosts in your CSP (webFontHosts.google from @absoluteui/theme), and register icons as ligatures: the element carries the font class and the icon name as text.

import { webFontHosts } from '@absoluteui/theme';
import { registerIcons, renderIcon } from '@absoluteui/icons';
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200';
document.head.append(link);
const csp = `style-src 'self' ${webFontHosts.google.styleSrc}; font-src 'self' ${webFontHosts.google.fontSrc}`;
registerIcons({ home: { kind: 'ligature', className: 'material-symbols-outlined', text: 'home' } });
const home = renderIcon('home');
[home.textContent, home.getAttribute('translate')]; // => ['home', 'no']
csp.includes('https://fonts.gstatic.com'); // => true

Material Icons (the older font) works the same way with className: 'material-icons'. Both are Apache 2.0 licensed.

How do I use Material Symbols or Material Icons as SVG instead of a font?

Section titled “How do I use Material Symbols or Material Icons as SVG instead of a font?”

SVG avoids loading a font and a third-party host. Take the path from the icon’s SVG file (for example from the @material-symbols/svg-400 package, imported as text by your bundler):

import homeSvg from '@material-symbols/svg-400/outlined/home.svg?raw';
import { registerIcons, renderIcon } from '@absoluteui/icons';
const viewBox = /viewBox="([^"]+)"/.exec(homeSvg)?.[1] ?? '0 -960 960 960';
const d = /\sd="([^"]+)"/.exec(homeSvg)?.[1] ?? '';
registerIcons({ home: { kind: 'svg', viewBox, paths: [d] } });
renderIcon('home').getAttribute('viewBox'); // => '0 -960 960 960'

How do I use Lucide, and make every component use it?

Section titled “How do I use Lucide, and make every component use it?”

Convert Lucide’s icon nodes with fromSvgNodes. A provider that maps the names components ask for to Lucide icons switches every component at once; unmapped names fall back to the built-in set.

import { Calendar, ChevronDown, Search, X } from 'lucide';
import { fromSvgNodes, resolveIcon, setIconProvider, type IconDefinition } from '@absoluteui/icons';
const lucideIcons: Readonly<Record<string, IconDefinition>> = {
close: fromSvgNodes(X),
'chevron-down': fromSvgNodes(ChevronDown),
calendar: fromSvgNodes(Calendar),
search: fromSvgNodes(Search),
};
setIconProvider({ resolve: (name) => lucideIcons[name] });
resolveIcon('close') === lucideIcons.close; // => true
resolveIcon('check').kind; // => 'svg' // not mapped: the built-in check

Lucide is ISC licensed. The same fromSvgNodes works for other sets that publish [tag, attributes] nodes.

How do I layer icons, for a badge or a counter?

Section titled “How do I layer icons, for a badge or a counter?”

A layers definition stacks icons and short texts in one icon. Each layer can be scaled, moved (in em), rotated, flipped, placed in a corner, and coloured with a theme tone. Label the whole icon once.

import { renderIcon } from '@absoluteui/icons';
const dot = { kind: 'svg', viewBox: '0 0 24 24', nodes: [['circle', { cx: 12, cy: 12, r: 12 }]] } as const;
const events = renderIcon({
kind: 'layers',
layers: [
{ icon: 'calendar' },
{ icon: dot, scale: 0.45, position: 'top-end', tone: 'error' },
{ text: '3', position: 'bottom-end', tone: 'error' },
],
}, { label: '3 events today', size: 'xl' });
[events.getAttribute('aria-label'), events.children.length]; // => ['3 events today', 3]

A provider is asked first for every name. Return a definition for the names you replace and undefined for the rest, which then come from the registry. setIconProvider(null) removes it.

import { builtInIcons, resolveIcon, setIconProvider, type IconDefinition } from '@absoluteui/icons';
const brand: Readonly<Record<string, IconDefinition>> = {
close: { kind: 'svg', viewBox: '0 0 20 20', stroke: true, paths: ['M5 5l10 10M15 5L5 15'] },
};
setIconProvider({ resolve: (name) => brand[name] });
resolveIcon('close') === brand.close; // => true
resolveIcon('check') === builtInIcons.check; // => true
setIconProvider(null);
resolveIcon('close') === builtInIcons.close; // => true

How do I change the icon of one component only?

Section titled “How do I change the icon of one component only?”

Pass a name or an inline definition in the component’s icons option (each component lists its icon slots in its API reference). Other instances are unaffected.

import { Spinner } from '@absoluteui/components/spinner';
const host = document.createElement('div');
document.body.append(host);
Spinner.create(host, { label: 'Saving', icons: { spinner: 'refresh' } });

Unknown names, unsafe or malformed definitions, and invalid sizes fail loudly, with the icon’s name in the error. Shape nodes accept geometry, fill/stroke (none or currentColor), fill rules, and opacity only: no event handlers, styles, links, or scripts. TypeScript already rejects a size like 'huge'; the run-time check covers values from untyped configuration (the cast below simulates one).

import { fromSvgNodes, registerIcons, renderIcon, resolveIcon } from '@absoluteui/icons';
resolveIcon('no-such-icon'); // => throws ICON_UNKNOWN
registerIcons({ broken: { kind: 'svg', viewBox: '0 0 24', paths: ['M0 0'] } }); // => throws ICON_INVALID
fromSvgNodes([['circle', { cx: 12, onclick: 'alert(1)' }]]); // => throws ICON_INVALID
renderIcon('check', { size: 'huge' as '1px' }); // => throws ICON_INVALID_SIZE

fromFontAwesome

Converts a Font Awesome SVG icon definition (for example faUser from @fortawesome/free-solid-svg-icons) into an AbsoluteUI svg definition (filled with the text colour). Duotone definitions become one path per layer.

function fromFontAwesome(definition: FontAwesomeIconLike): IconDefinition;

Example:

fromFontAwesome({ icon: [448, 512, [], 'f007', 'M224 256a128 128 0 1 0 0-256z'] });
// => { kind: 'svg', viewBox: '0 0 448 512', paths: ['M224 256a128 128 0 1 0 0-256z'] }

fromSvgNodes

Converts [tag, attributes] shape nodes, the format of Lucide’s lucide package (fromSvgNodes(Users)) and similar icon sets, into an AbsoluteUI svg definition. Attributes are validated like every other icon; unsupported ones throw ICON_INVALID.

function fromSvgNodes(nodes: readonly (readonly [string, Readonly<Record<string, string | number | undefined>>])[], options?: FromSvgNodesOptions): IconDefinition;

Example:

fromSvgNodes([['circle', { cx: '12', cy: '12', r: '10' }], ['path', { d: 'M12 8v4' }]]).kind; // => 'svg'

registerIcons

Register or replace named icons in the built-in registry.

function registerIcons(icons: Readonly<Record<string, IconDefinition>>): void;

renderIcon

Render an icon element. Decorative by default; semantic when label is set.

function renderIcon(ref: IconRef, options?: RenderIconOptions): Element;

Example:

const icon = renderIcon('calendar', { size: 'lg' });
icon.getAttribute('aria-hidden'); // => 'true'
icon instanceof SVGElement ? icon.style.fontSize : ''; // => 'var(--aui-icon-size-lg, 1.5rem)'

resolveIcon

function resolveIcon(ref: IconRef): IconDefinition;

setIconProvider

Set a global icon provider. It is consulted before the registry, so a corporate icon set can replace every AbsoluteUI icon. null removes it.

function setIconProvider(next: IconProvider | null): void;

builtInIcons

Built-in icon set: original, minimal 24x24 stroke geometry.

const builtInIcons: Readonly<Record<string, IconDefinition>>;

FontAwesomeIconLike

Shape of a Font Awesome icon definition (@fortawesome/*-svg-icons): icon is [width, height, ligatures, unicode, pathData]. Typed structurally; no Font Awesome import.

interface FontAwesomeIconLike {
readonly icon: readonly [number, number, unknown, unknown, string | readonly string[]];
}

FromSvgNodesOptions

interface FromSvgNodesOptions {
readonly viewBox?: string;
readonly stroke?: boolean;
readonly strokeWidth?: number;
}

IconLayer

One layer of a layers icon: an icon or a short text (a counter), optionally transformed, placed, and coloured. Offsets x/y are in em (fractions of the icon size).

interface IconLayer {
readonly icon?: IconRef;
readonly text?: string;
readonly scale?: number;
readonly x?: number;
readonly y?: number;
readonly rotate?: number;
readonly flip?: 'horizontal' | 'vertical' | 'both';
readonly position?: IconLayerPosition;
readonly tone?: IconTone;
readonly className?: string;
}

IconProvider

interface IconProvider {
resolve(name: string): IconDefinition | undefined;
}

RenderIconOptions

interface RenderIconOptions {
label?: string;
className?: string;
size?: IconSize;
doc?: Document;
}

IconDefinition

type IconDefinition =
{
readonly kind: 'svg';
readonly viewBox: string;
readonly paths?: readonly string[];
readonly nodes?: readonly SvgNode[];
readonly stroke?: boolean;
readonly strokeWidth?: number;
}
| {
readonly kind: 'factory';
readonly create: (doc: Document) => Element;
}
| {
readonly kind: 'class';
readonly className: string;
}
| {
readonly kind: 'ligature';
readonly className: string;
readonly text: string;
}
| {
readonly kind: 'layers';
readonly layers: readonly IconLayer[];
};

IconLayerPosition

Corner or centre of a layered icon, for badges and counters.

type IconLayerPosition = 'center' | 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end';

IconRef

An icon name resolved through the provider/registry, or an inline definition.

type IconRef = string | IconDefinition;

IconSize

Theme icon sizes (icon-size-xs 0.75rem … icon-size-xl 2rem), or a CSS length such as '1.125rem' or '20px'.

type IconSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | `${number}${'px' | 'rem' | 'em' | 'pt' | '%'}`;

IconTone

Colours a layer can take from the theme.

type IconTone = 'primary' | 'success' | 'warning' | 'error' | 'muted';

SvgNode

One SVG shape as [tag, attributes], the format Lucide and many icon sets publish. Geometry attributes are numbers or numeric strings; fill and stroke may be 'none' or 'currentColor'; fill-rule/clip-rule 'nonzero' or 'evenodd'; opacity 0 to 1.

type SvgNode = readonly [SvgNodeTag, Readonly<Record<string, string | number>>];

SvgNodeTag

SVG shape elements an svg definition may contain.

type SvgNodeTag = 'circle' | 'ellipse' | 'line' | 'path' | 'polygon' | 'polyline' | 'rect';