foundations
Iconography
Lucide React, nothing else. Two icon libraries doubles the bundle and fractures visual consistency — one library holds the line.
Read the full specLibrary grid
A representative slice of the Lucide set as Wolf consumes it. Import by name from lucide-react; tree-shaking keeps the bundle tight.
- Home
- ShieldAlert
- Shield
- Siren
- AlertTriangle
- MapPin
- Users
- User
- Bell
- MessageSquare
- Phone
- BarChart3
- Activity
- Calendar
- Clock
- Search
- Filter
- Settings
- Menu
- Plus
- X
- Check
- ChevronDown
- ArrowRight
- Eye
- Lock
- Edit
- Copy
- Share
- Download
- RefreshCw
- File
- Info
- Zap
- Star
- Trash2
import { ShieldAlert, MapPin } from "lucide-react";
<ShieldAlert className="size-5" aria-hidden />Size scale
Eight sizes, four-pixel increments up to 3xl. Never 13, 15 or 18 — they fracture the grid.
- xs· 12pxclassName="size-3"Inline in body at xs text
- sm· 14pxclassName="size-3.5"Inside small buttons
- base· 16pxclassName="size-4"Default inline with body text
- md· 20pxclassName="size-5"Inside buttons (md), nav items
- lg· 24pxclassName="size-6"Inside buttons (lg), headers
- xl· 32pxclassName="size-8"Feature icons
- 2xl· 48pxclassName="size-12"Empty-state hero icons
- 3xl· 64pxclassName="size-16"Hero / marketing only
Stroke width
Default 1.5 at 24×24. Bump to 2 at 16px or below — 1.5 strokes disappear at low DPR.
- strokeWidth=1rarely
- strokeWidth=1.25rarely
- strokeWidth=1.5canonical
- strokeWidth=2use at ≤16px
<AlertTriangle className="size-5" /> { /* 1.5 default */ }
<AlertTriangle className="size-4" strokeWidth={2} /> { /* 2 at small size */ }Semantic colouring
Icons inherit currentColor by default. Override only for semantic intents — success, warning, destructive, info.
- Success
- Warning
- Destructive
- Info
Decorative vs semantic
If the icon duplicates a visible label, hide it from screen readers. If it carries meaning alone, give it an aria-label.
{ /* Decorative — label is present */ }
<button><Trash2 aria-hidden className="size-4" /> Delete</button>
{ /* Semantic — icon-only */ }
<button aria-label="Close dialog"><X className="size-4" /></button>Forbidden patterns
Each of these breaks a rule in the library. Lucide ships clean; don't undo it.
- Mixing icon libraries (Heroicons + Lucide).
- Emoji in product UI — rendering varies per platform.
- CSS transform: scale() on an icon — distorts strokes.
- Hardcoded hex fills — breaks theming.
- Rotating Lucide icons to intermediate angles.
- Nesting icons inside icons.