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.