04 · Foundations
Iconography
One icon library, one stroke weight, one set of rules. Lucide ships with every shadcn project and covers every functional icon you’ll need. The diagonal up-right arrow stays as the signature gesture on CTAs, links, and “read more” affordances — rendered via Lucide’s arrow-up-right.
The arrow
Path
M4 12L12 4M12 4H5M12 4V11
Viewbox
0 0 16 16
Stroke
currentColor · 1.5px
Linecap / join
round · round
Default size
14×14 (inline) · 12×12 (small)
File
assets/arrow.svg
<!-- Canonical markup --> <svg width="14" height="14" viewBox="0 0 16 16" fill="none"> <path d="M4 12L12 4M12 4H5M12 4V11" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> </svg>
Hover behavior
On hover, the arrow shifts up and to the right: transform: translate(2px, -2px). The transition is 200ms ease. Paired with the pill button, the button fills and the arrow moves together.
Hover the button to see the arrow nudge and the button fill.
The icon library — Lucide
Lucide is the icon library. ~1,400 outline icons, consistent 24×24 grid, stroke-customizable. It’s shadcn’s default, so every Button, Dialog, and Select primitive already uses it.
License
ISC (same family as MIT). Free for commercial use, modification, and redistribution. No attribution required in your UI. Ship it anywhere.
Color toggle
Every icon renders in currentColor, so it inherits whatever text color surrounds it. Click through to preview:
Coloring rules
- Default:
currentColor. Icons inherit the surrounding text color — usually--text-mutedfor inactive states,--foregroundfor primary contexts. - Active / emphasized:
--accent(indigo). For selected sidebar items, active toggles, primary actions. - Disabled / tertiary:
--text-faint. - Never tint a decorative icon in
--destructive,--success, or--warning. Those colors are for status badges, not icons-as-decoration.
Sizing
- 14px — inline with body text, inside small buttons
- 16px — most common; toolbars, row actions, sidebar nav
- 18–20px — featured list items, section headers
- 22–24px — empty states, hero cards, large affordances
Stroke weight: always 1.5 (matches the pill button border).
Install
Shadcn projects already have it. For React without shadcn:
npm install lucide-react
Usage:
import { Search, Settings } from 'lucide-react' <Search className="h-4 w-4" strokeWidth={1.5} />
What to avoid
Even with Lucide, a few rules stay non-negotiable:
- ×Unicode arrows (→ ↗ ➜) — use Lucide’s
arrow-up-right - ×Mixing icon libraries (no Heroicons, no Phosphor)
- ×Emoji (🚀 ✨ 👉) in UI chrome
- ×Filled / solid variants as default (outline only)
- ×Multi-color icons (always single stroke color)
- ×Stroke weights other than 1.5
If a surface seems to need more iconography, it usually needs better typography and spacing instead.
In use
Three common placements: