Skip to content
AstroCraft Docs
On this theme

Icons

Indexa has no icon dependency. src/components/svg/icons/ holds 578 inlined 24×24 SVGs behind one typed component, and none of them reaches client JavaScript — icons inline into the HTML at build time.

---
import { Icon } from "@components/svg/icons";
---

<Icon name="activity" />
<Icon name="trash-01" size="lg" class="text-error" />
<Icon name="search-01" title="Search" />

name is a typed IconName, so a typo fails astro check rather than rendering an empty box, and your editor autocompletes all 578. size is sm/md/lg/xl — size-4 through size-8, default md — or pass class="size-6" for anything else.

Colour is currentColor throughout, so any text-* token recolours a glyph. Decorative is the default (aria-hidden="true"); passing title promotes the icon to role="img" with a <title>, which is what you want for an icon that is the only content of a button.

Icon.astro follows the same primitive contract as everything in ui/ — exported tv() config, native svg props, merged class, data-slot="icon".

What is in the set

Two Figma Community files. The bulk are Stratis UI Icons line icons, ported frame by frame: General, Arrows (partly), Media & Devices, Alerts, Security, Images, Files, Charts, Development, Communication, Editor. On top is a Social/brand set — filled marks for facebook, instagram, tiktok, threads, messenger, whatsapp, telegram, behance, github, discord, linkedin, slack, line, apple, google, pinterest, google-play and bluesky.

Line icons carry their own stroke width; brand marks are filled silhouettes whose negative space is a path knockout, so they render in one tone rather than in brand colours. That is a deliberate constraint of the approach — a single-tone mark recolours with the text around it.

The registry and its ceiling

icons.ts is auto-generated and 465 KB. It exports ICONS (name to inner markup), the IconName union and an iconNames array. Do not hand-edit it; a regeneration would overwrite you.

The size is a stated ceiling rather than an accident. Build-time inlining means a page ships only the glyphs it renders, so 465 KB of registry costs nothing in the browser — as long as nothing imports it from a client script. The ponytail: note in the README says exactly that, and the saved dashboard is where it came true: importing the registry into Sections/Saved/saved.ts shipped roughly 475 KB of SVG to one page. The fix in place now is a four-glyph GLYPHS map inside that module holding copies of the icons it actually renders, with a note to add to it if a fifth appears.

If a client script ever needs the whole set, the upgrade path is per-file .svg imports as Astro native SVG components, or a sprite. Copying four glyphs is cheaper than either, and it is the right call until a page needs forty.

Adding one glyph

There is no hand-written half: all 578 names come from the generated table, so <Icon>’s type union and the registry cannot disagree. That is worth knowing before you add a one-off glyph, because there is no extras map to drop it into — either run it through the generator, or add one yourself in icons.ts’s sibling and merge it in index.ts (the shape other themes in this family use is an EXTRAS object spread over ICONS).

Check first whether the set already has what you want under another name. With 578 glyphs the answer is usually yes, iconNames is exported so you can list them, and /examples/ui already renders the whole set.

Regenerating from Figma

The full runbook is in src/components/svg/icons/README.md. The shape of it: call the Figma MCP get_design_context on a category frame node, collect { id, name, url } into a manifest keyed by node id — not by name, because the source’s names are not unique — then run the generator, which downloads each SVG, normalizes colour to currentColor, flattens bare <g> wrappers, strips ids, scale-fits the few off-grid viewBoxes, dedupes by cleaned content and rewrites icons.ts.

Three things in that process are worth knowing before you start. The cleaner asserts on anything unexpected — a <g transform>, a colour it could not normalize, an empty icon — so a bad export fails loudly instead of shipping a broken glyph. The source file mislabels some glyphs, and the fix is a node-id-keyed name override in the generator, never a hand edit to icons.ts. And a cross-file name clash is reported and skipped rather than silently overwritten, which is why the brand file’s youtube was dropped in favour of the UI set’s.

The generator is idempotent: identical glyphs dedupe by content, so re-running it never double-adds. get_design_context also counts against a per-account Figma MCP quota, so pull a few frames at a time.

NEXT STEPMotion