01Button
sm 32 · default 40 · lg 48 · icon 40- One primary button per view. Secondary actions use outline or secondary; destructive actions use destructive and need confirmation.
- Labels start with a verb, within three words or six Chinese characters; icon-only buttons need an aria-label.
- Disabled is 40% opacity; never hide a button to show it is unavailable.
// components/ui/button.tsx
const buttonVariants = cva(
[
"relative isolate inline-flex shrink-0 items-center justify-center gap-2 overflow-hidden border border-transparent font-medium whitespace-nowrap select-none",
"transition-[translate,background-color,border-color,color,text-decoration-color] duration-(--duration-fast) ease-standard",
"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring",
"disabled:pointer-events-none disabled:opacity-40",
],
{
variants: {
variant: {
default: [
"bg-primary text-primary-foreground hover:bg-blue-600 active:bg-blue-700 hover:-translate-y-px active:translate-y-0 motion-reduce:hover:translate-y-0",
"before:absolute before:inset-y-0 before:left-0 before:-z-10 before:w-1/3 before:-translate-x-[150%] before:-skew-x-12 before:bg-white/20",
"hover:before:translate-x-[320%] hover:before:transition-transform hover:before:duration-(--duration-scene) hover:before:ease-emphasized motion-reduce:before:hidden",
],
secondary: "bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklab,var(--secondary),var(--foreground)_8%)] hover:-translate-y-px active:translate-y-0 motion-reduce:hover:translate-y-0",
outline: "border-strong bg-background text-foreground hover:border-foreground hover:-translate-y-px active:translate-y-0 motion-reduce:hover:translate-y-0",
ghost: "text-foreground hover:bg-surface active:bg-surface-2",
link: "text-link underline decoration-transparent decoration-1 underline-offset-4 hover:decoration-current",
destructive: "bg-destructive text-destructive-foreground hover:bg-[color-mix(in_oklab,var(--destructive),var(--foreground)_14%)] hover:-translate-y-px active:translate-y-0 motion-reduce:hover:translate-y-0",
},
size: {
sm: "h-8 px-3 text-[13px] [&_svg]:size-3.5",
default: "h-10 px-4 text-sm [&_svg]:size-4",
lg: "h-12 px-5 text-[15px] [&_svg]:size-4.5",
icon: "size-10 [&_svg]:size-4.5",
},
},
compoundVariants: [{ variant: "link", class: "h-auto px-0" }],
defaultVariants: { variant: "default", size: "default" },
},
)
<Button>Deploy</Button>
<Button variant="outline" size="sm"><Icon name="download" />Download</Button>