Design System

Icons

One icon library, five legal sizes, and a hard requirement that an icon never carries meaning on its own. Icons support labels; they do not replace them unless the control is unmistakable.

What is this?

Lucide React is the only icon source. Sizes come from --size-icon-xs (12px) through --size-icon-xl (32px), and icon-only controls are always rendered through IconButton.

When to use it

  • Reinforcing a labelled action or a status
  • Compressing a repeated, unmistakable control into a single tap target
  • Marking rows, list items and menu entries consistently

How to use it

  • Import the icon from lucide-react and size it with an icon-size token
  • Match icon size to the control size — small controls take xs, default take sm
  • Give icon-only controls an accessible label and a Tooltip

What to avoid

  • Custom SVGs, emoji, or a second icon library
  • Icons as the only indicator of state or meaning
  • Arbitrary pixel sizes such as size-[18px]

Size tokens

Lucide React is the only icon library.

icon-xs

icon-sm

icon-md

icon-lg

icon-xl

Size assignment

Which icon size belongs with which control.
TokenValueUse with
--size-icon-xs12pxSmall buttons, badges, chips, table meta
--size-icon-sm16pxDefault buttons, inputs, menu items, nav links
--size-icon-md20pxLarge controls, section headers, feature rows
--size-icon-lg24pxFeature callouts, dialog headers
--size-icon-xl32pxEmpty and error states only

Common actions

Use the same icon for the same action everywhere — recognition is the point.

Create
Search
Filter
Export
Settings
Notifications
Delete
Confirm
Expand
Continue

Icon-only controls

IconButton supplies the accessible name and the 24px minimum target; the Tooltip explains the action.

Rules

Three non-negotiable icon rules

1. Lucide React only. No custom SVGs, no second icon library, no emoji standing in for an icon.

2. Token sizes only. Every icon uses one of the five icon-size tokens, applied through size-(--size-icon-*).

3. Icon-only controls use IconButton and a Tooltip. The label prop gives the control an accessible name; the tooltip gives sighted users the same information. An unfamiliar control without a tooltip is a bug.

Do & don't

Do

  • Mark decorative icons aria-hidden when a visible label already names the action.
  • Keep icon meaning stable across the product — one icon, one action.
  • Pair status icons with status colour so colour is never the only channel.
  • Use the xl size only inside empty and error states.

Don't

  • Do not put an icon on every button — reserve them for scanning value.
  • Do not use an icon-only control for a destructive action outside a repeated row.
  • Do not resize an icon with width/height attributes.
  • Do not rotate or recolour an icon to invent a new meaning.

Why it is designed this way

Constraining the library and the size set means icons compose predictably with the type scale: a 16px icon always sits on a 16px label, so toolbars and menus align without per-case adjustment. Routing icon-only controls through IconButton is what guarantees the accessible name and the 24px minimum pointer target every time.