asChild prop that lets you render any element — such as a React Router <Link> — with button styles.
Import
Basic usage
Variants
Use thevariant prop to control the visual style of the button.
| Variant | Description |
|---|---|
default | Primary action. Filled with bg-primary. |
destructive | Destructive or irreversible actions. Filled with bg-destructive. |
outline | Secondary action with a visible border and transparent background. |
secondary | Lower-emphasis action. Filled with bg-secondary. |
ghost | No background; hover shows bg-accent. Useful for inline or toolbar buttons. |
link | Renders as styled text with an underline on hover. No background or border. |
Sizes
Use thesize prop to control the button’s dimensions.
| Size | Height | Padding |
|---|---|---|
default | h-9 | px-4 py-2 |
sm | h-8 | px-3 |
lg | h-10 | px-6 |
icon | size-9 (square) | — |
icon-sm | size-8 (square) | — |
icon-lg | size-10 (square) | — |
The asChild prop
Set asChild to true to merge the button’s props and styles onto its immediate child element instead of rendering a <button> tag. This uses the Radix UI Slot primitive.
This is the recommended pattern for rendering a button that navigates to a route:
<a> element (from React Router’s <Link>) that carries all button Tailwind classes. No nested <button> is created.
When using
asChild, the child element must accept className and event handler props. React Router’s <Link> and standard HTML elements both satisfy this requirement.buttonVariants utility
Use the exported buttonVariants function to apply button styles to elements that you cannot wrap with <Button>, such as elements rendered by third-party libraries.
buttonVariants is produced by class-variance-authority and accepts the same variant and size options as the <Button> component.
Props
All native<button> HTML attributes are accepted via prop spreading. The component-specific props are:
Visual style. One of
default, destructive, outline, secondary, ghost, link.Dimensions. One of
default, sm, lg, icon, icon-sm, icon-lg.When
true, renders the Radix Slot component, merging button props onto the child element instead of creating a <button> tag.Additional Tailwind classes merged via
cn() (clsx + tailwind-merge). Use this to extend or override default styles.Disables the button. Applies
pointer-events-none and opacity-50 via Tailwind. Passed through to the underlying element.Real-world examples
Ghost button to clear a search field
Navigation buttons on the home page
Accessibility
- Focus ring — A visible
ringappears on keyboard focus viafocus-visible:ring-ring/50 focus-visible:ring-[3px], satisfying WCAG 2.4.7. - Disabled state —
disabled:pointer-events-none disabled:opacity-50prevents interaction and provides a visual cue. - Invalid state —
aria-invalidon the button triggers aring-destructiveoutline, useful for form error states. - Icon buttons — Always provide an
aria-labelwhen usingsize="icon",size="icon-sm", orsize="icon-lg"because there is no visible text label.