Button
Triggers an action or submits a form. For navigation, use Button asChild with a
Link — never nest a <button> inside <a>.
Variants
Primary
The most important action on a page. White text on blue background.
<Button>Save report</Button>
<Button size="sm">Save report</Button>
<Button size="lg">Save report</Button> Secondary
Supporting or lower-priority actions. Outlined style.
<Button variant="secondary">Cancel</Button> asChild — rendering a link as a button
Why does this exist? An <a> inside a <button> is invalid HTML. asChild lets you apply button styles to any child element — typically
a router Link — so the rendered HTML is a single <a>, not a
button wrapping a link. This is correct semantically and passes HTML validation. It is the
recommended pattern from Radix UI and ariakit.
Use asChild whenever something navigates to a new page but should look like a
button. Use a plain <button> (or Button without asChild) when the action stays on the same page.
// Navigates to a new page → use asChild + Link
<Button asChild>
<Link to="/projects/new">New project</Link>
</Button>
// Submits a form → plain button, no asChild needed
<Button type="submit">Create project</Button> Disabled state
<Button disabled>Save report</Button> Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'primary' | 'secondary' | 'primary' | Visual style |
size | 'sm' | 'md' | 'lg' | 'md' | Button size |
asChild | boolean | false | Render styles onto child element instead of a <button>. Child must be
a single React element (e.g. a router Link). |
...props | ButtonHTMLAttributes | — | All native button attributes (type, disabled, onClick, …). Not forwarded when asChild is true. |