Button
A versatile button component with multiple variants, sizes, and states. Supports icons, loading state, and composition via asChild.
Installation
pnpm dlx @hex-core/cli add buttonVariants
Different visual styles
<>
<Button variant="default">Primary</Button>
<Button variant="outline">Outline</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="destructive">Delete</Button>
<Button variant="link">Link</Button>
</>With loading state
Button showing a spinner while loading
<Button loading>Submitting...</Button>As link
Button rendered as an anchor tag
<Button asChild>
<a href="/login">Login</a>
</Button>API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | default | The visual style of the button |
size | "default" | "sm" | "lg" | "icon" | default | The size of the button |
asChild | boolean | false | Render as a Slot component, merging props with the child element. Use to render as a link or other element. |
loading | boolean | false | Show loading spinner and disable interaction |
disabled | boolean | false | Disable the button |
className | string | — | Additional CSS classes to merge with the component styles |
AI Guidance
When to use
Use for clickable actions: form submissions, confirmations, triggering operations. Use 'default' variant for primary CTAs, 'outline' or 'secondary' for less important actions, 'ghost' for toolbar-style actions.
When not to use
Don't use for navigation between pages (use Link or anchor with asChild). Don't use 'destructive' for non-dangerous actions. Don't use for toggling state (use Toggle or Switch).
Common mistakes
- Using 'destructive' variant for non-destructive actions
- Nesting interactive elements inside asChild button
- Missing aria-label when using icon-only size='icon' variant
- Using onClick for navigation instead of asChild with a link
Accessibility
Automatically handles focus ring, disabled state, and aria attributes. Icon-only buttons MUST have aria-label. Loading state automatically sets disabled.
Related components
Token budget: 500