Foundations / Icons

Icons

Icons are the glyph set Alpha publishes, for use inside its own components and in your markup. They take their colour and their size from whatever they sit in, so a glyph dropped into a button or a tag matches it without being told to.

On this page

The set is drawn on a 20×20 grid, almost all of it at a 2px stroke with round caps and joins, and painted in currentColor. Those four decisions are the whole foundation, and each of them is doing work: a shared grid is what makes two icons look like a pair rather than two drawings, a shared stroke weight is what stops one reading as bolder than its neighbour, and currentColor is what lets a glyph follow a disabled label, a hover state and a theme toggle without a prop for any of them.

They ship as one component per drawing, from their own entry point — @growth-protocol-ai/alpha/icons. That split is the point of it: the root entry point stays the component API rather than the glyph vocabulary, and an application that imports two icons ships two rather than the set. There is no icon on the root barrel and no way to reach one from it.

import { Button } from '@growth-protocol-ai/alpha';
import { PlusIcon, SearchIcon } from '@growth-protocol-ai/alpha/icons';

<SearchIcon />
<SearchIcon size="lg" />
<SearchIcon aria-label="Search" />

<Button iconLeft={<PlusIcon />}>Add member</Button>

The slots that take one are not closed the same way: Button's iconLeft and iconRight, Dropdown's leading and Modal's icon are all ReactNode, so nothing forces a glyph to come from Alpha, and each component normalises whatever arrives. That is also why the slot takes the element and not the component: iconLeft={<PlusIcon />}. If you are typing a slot of your own against the component instead, AlphaIcon is the type for it.

A glyph is drawn at 20px on a 20×20 grid with a 2px stroke and round caps — which is what makes them look like one hand rather than a collection. The count is under the field, so it is whatever the package currently ships. They are drawn in currentColor, so each cell below is only setting a text colour and the icons follow it; toggle the theme and nothing here is repainted by name.

The labels drop the suffix every export shares — Trash is TrashIcon — so the grid reads as drawings rather than as a column of the same word; click one for its exact import. The field matches the descriptions as well as the names, so delete reaches TrashIcon without your knowing what it is called.

The list is closed: these are drawings made for this set, and a Lucide or Heroicons glyph beside them reads as a mistake rather than a substitute. Names describe the drawing, not the feature it happens to serve — LayoutIcon rather than UiBuilderIcon, RocketIcon rather than WorkflowsIcon — because a shared package outlives one product's vocabulary. The brand marks are the exception — TalosIcon, ZeusIcon and AskZeusIcon carry the product name, because that is what someone reaching for one will search for.

199 of 199

Not all of them are pure outlines. A good many are drawn solid — the triangles, the letterforms, the paint wells in PaletteIcon — and some mix the two, the way RocketIcon fills only its porthole, because that is how the library draws them. For TrashIcon the weight is the point — it is the one action in a row that cannot be taken back, and a solid glyph says so before the label does.