Skip to main content
Gelium UI
Blog View source 0.6.5 Theme Gallery
Recipe

Native behavior · Vercel · Gelium defaults · Native baseline

Appearance
Menu

Published · Updated · v0.6.5 · MIT License · Source: icon.md

Icon

Decorative icon Named by visible text Existing iconExisting iconExisting iconExisting iconExisting icon

Icon is the Gelium-only primitive for trusted inline SVG glyphs. Use icons when a control or a message needs a small, themeable graphic that ships with the server render. All icons are resolved server-side as trusted template.HTML markup — icon markup must never be built from user input.

Guidance

When to use

Use icons when a control or a message needs a small, themeable graphic that ships with the server render.

When not to use

Do not use an icon where text alone is clearer. Never make an icon the only signal: decorative icons must sit next to visible text, and meaningful icons must be named by visible text. Never build icon markup from user input — glyphs are trusted, server-resolved markup.

Usability

  • The shared .ui-icon class gives every icon consistent 24 px sizing and a currentColor fill so the glyph matches surrounding text automatically.
  • Icons are resolved server-side as trusted template.HTML markup; pass only internal glyphs.
  • Decorative icons must include aria-hidden="true" and focusable="false".

Accessibility

  • Decorative icons must be aria-hidden="true" and focusable="false" and must sit next to visible text or another accessible name.
  • An icon that carries meaning is named by visible text beside it, never by an aria-label alone.
  • The currentColor fill keeps icons at the surrounding text's contrast in every theme, including forced-colors mode.

See Choose the right control for the cross-component decision.

Material Symbols set

Gelium UI ships a curated set of Material Symbols (Apache-2.0, from google/material-design-icons) as trusted server-resolved inline SVGs. The set is generated by scripts/copy-icons.mjs into internal/app/icons.go and embedded in the binary — consumers never fetch icon files at runtime, and every glyph is themeable through currentColor.

The curated allowlist (38 glyphs, identical to the ICONS array in scripts/copy-icons.mjs).

add, arrow_back, arrow_downward, arrow_forward, arrow_upward, check,
chevron_left, chevron_right, close, delete, edit, error, home, info, menu,
more_vert, refresh, save, search, settings, warning, person, notifications,
share, star, thumb_up, visibility, visibility_off, lock, send, download,
upload, calendar_today, schedule, more_horiz, add_circle, dark_mode,
light_mode

Each glyph keeps the Material Symbols 960-grid coordinate space (viewBox="0 -960 960 960"); the .ui-icon class owns the rendered size. To add a glyph, extend the ICONS allowlist in scripts/copy-icons.mjs, rebuild, and let the contract test verify the new row carries aria-hidden, focusable="false", and currentColor.

The .ui-icon utility

The shared .ui-icon class gives every icon consistent 24 px sizing, a fixed flex size, and a currentColor fill. The glyph matches surrounding text automatically.

Accessibility contract

Decorative icons must be aria-hidden="true" and focusable="false" and must sit next to visible text or another accessible name. An icon that carries meaning is named by visible text beside it and never by an aria-label alone. The examples below follow that contract.