Icons

Two complementary libraries — lucide for UI, simple-icons for brand logos. Per-framework packages.

Two libraries, zero overlap

Lucide v1.0 removed brand logos (trademark, maintenance). Simple Icons ships only brand logos, no UI primitives. The two packages cover disjoint domains — you always know which one to reach for.

Lucide

UI primitives — arrows, form states, navigation, status.

Simple Icons

Brand logos — GitHub, X, Figma, Stripe, and ~3200 more.

GitHubXFigmaStripeVercelDiscord

UI icons — Lucide

Import individually for tree-shaking. Default size is 1em — override with size-4 or size-5 utilities.

ArrowRight
Bell
Check
ChevronDown
Heart
Menu
Plus
Search
Settings
Sparkles
Trash2
User

Brand logos — Simple Icons

Prefixed with Si. Single-color logos — colored variants exist with a Hex suffix (SiGithubHex).

GitHub
SiGithub
X
SiX
Figma
SiFigma
Notion
SiNotion
Discord
SiDiscord
Stripe
SiStripe
Vercel
SiVercel
Linear
SiLinear

Per-framework packages

Both libraries ship framework-specific packages with identical icon names. Blocks and components are copy-paste per framework — imports swap automatically.

FrameworkUI iconsBrand logos
Reactlucide-react@icons-pack/react-simple-icons
Vuelucide-vue-next@icons-pack/vue-simple-icons
Sveltelucide-svelte@icons-pack/svelte-simple-icons

Coloring

Icons inherit color via currentColor. The parent element sets the text color — the icon follows. Variants (info, success, warning, destructive) simply swap the parent's text utility via the [&>svg]:text-* selector. The icon itself stays untouched.

Five variants, one pattern

Each Alert passes a Lucide icon as child. The variant class paints it via [&>svg]:text-*.

How it's wired

The selector lives on the wrapper's CVA — the icon stays prop-free.

alert.tsx
const alertVariants = cva(
  "... [&>svg]:size-4",
  {
    variants: {
      variant: {
        default:     "[&>svg]:text-fg-secondary",
        info:        "[&>svg]:text-accent",
        success:     "[&>svg]:text-success",
        warning:     "[&>svg]:text-warning",
        destructive: "[&>svg]:text-destructive",
      },
    },
  },
);
usage.tsx
<Alert variant="success">
  <CheckCircle2 />
  <AlertTitle>Saved</AlertTitle>
</Alert>
coloring.tsx
// Wrong — hardcoded on the icon
<Bell stroke="#3b82f6" className="size-5" />

// Right — parent drives color, icon inherits
<div className="text-accent">
  <Bell className="size-5" />
</div>

// Or shorthand (same thing — Bell is just a span with currentColor SVG)
<Bell className="size-5 text-accent" />

Usage

Never inline raw SVG. Always import from the right package. Never mix a brand logo into a component that the design system publishes (blocks only).

import.tsx
import { Search, Settings } from "lucide-react";
import { SiGithub, SiX } from "@icons-pack/react-simple-icons";

<Search className="size-4" />
<SiGithub className="size-4" />
install.sh
pnpm add lucide-react @icons-pack/react-simple-icons