action

Button

A clickable action. Supports variants, sizes, icon-only buttons, loading state and links.

npx blankui add button

When to use

  • Trigger an action like save, submit, delete or open a dialog.
  • Style a link as a button with asChild.

Use something else when

  • Navigating to another page inside text. Use a plain link (<a> or your router's Link).
  • Switching between views of the same content. Use tabs.
  • Toggling a setting on or off. Use checkbox.

Import

import { Button } from "@/components/ui/button"

Variants

VariantUse for
defaultThe main action in a view. One per view.
secondaryA second, less important action.
outlineCancel, back, and other neutral actions.
ghostToolbar and icon actions with little weight.
destructiveDelete or other actions that cannot be undone
linkAn action that should look like a link.

Sizes: sm, default, lg, icon.

Examples

<Inline gap={2} justify="end">
  <Button variant="outline">Cancel</Button>
  <Button type="submit" loading={isSaving}>
    Save changes
  </Button>
</Inline>

Icon buttons must have an aria-label. TypeScript reports an error without it.

import { Trash } from "lucide-react"

;<Button size="icon" variant="ghost" aria-label="Delete project">
  <Trash />
</Button>

Icons next to text go before the text:

import { Plus } from "lucide-react"

;<Button>
  <Plus /> New project
</Button>

Links that look like buttons:

<Button asChild variant="outline">
  <a href="/pricing">See pricing</a>
</Button>

Notes

  • type defaults to "button", so a Button inside a form does not submit it. Use type="submit" for the submit button.
  • loading shows a spinner, disables the button and sets aria-busy.

Mistakes to avoid

AvoidInstead
<button className=...> (a raw button element)<Button>
<Button className="bg-red-500"><Button variant="destructive">
<Button size="icon"><Trash /></Button> without a label<Button size="icon" aria-label="Delete"><Trash /></Button>
<Button><a href=...>Docs</a></Button> (a link inside a button)<Button asChild><a href="/docs">Docs</a></Button>
{isSaving ? <Spinner /> : 'Save'} with disabled={isSaving}<Button loading={isSaving}>Save</Button>
Several default (primary) buttons side by sideOne default button, the rest variant="outline" or "ghost"

Install with the shadcn CLI: npx shadcn add https://blank.vageshwar.dev/r/button.json