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.

PropTypeDefaultDescription
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
disabledbooleanfalseDisables the button (opacity 50%, no pointer events)
classNamestring---Additional CSS classes to merge
childrenReactNode---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.

VariantDefaultHoverFocusActiveDisabled
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.

Sergiy Klimkovych

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