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 me

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-muted for inactive states, --foreground for 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:

On a pill

Read

On a text link

View project

On a card

Field notes