Button
Primary interaction element. Built on Base UI ButtonPrimitive with class-variance-authority (CVA) for variant composition. Use sparingly -- max 1 primary button per visible viewport.
Variants
Six visual variants to communicate different levels of emphasis and intent.
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | "default" | "secondary" | "outline" | "ghost" | "destructive" | "link" | "default" | Visual style of the button |
| size | "default" | "xs" | "sm" | "lg" | "icon" | "icon-xs" | "icon-sm" | "icon-lg" | "default" | Size of the button |
| disabled | boolean | false | Disables the button (opacity 50%, no pointer events) |
| className | string | --- | Additional CSS classes to merge |
| children | ReactNode | --- | Button content |
States Matrix
Every combination of variant and interactive state. Hover, focus, and active states are force-applied via inline styles and CSS overrides so all states are visible simultaneously.
| Variant | Default | Hover | Focus | Active | Disabled |
|---|---|---|---|---|---|
| default | |||||
| secondary | |||||
| outline | |||||
| ghost | |||||
| destructive | |||||
| link |
Sizes
Four text sizes plus four icon-only sizes for different contexts.
Icon + Label
Compose an icon with visible text by adding data-icon="inline-start" (or "inline-end") to the icon element — it tells the button variant to trim its own padding on that side (px-2.5 → pl-2/pr-2), since the icon plus the gap-1.5 token already carry the visual weight there. Previously defined in buttonVariants but never used anywhere in the app until this example.
Icon Buttons
Use icon sizes for toolbar actions and compact controls. Lucide icons at 16px.

Need a design system like this?
I design and build products end‑to‑end — from first idea and design system to production‑ready code, ready to hand off to your development team.
Product Designer | AI Design Engineer | Designer for Startups | Mobile & Complex SaaS | from Idea to Product | Framer Developer