Button

Buttons are the primary interactive elements for triggering actions.

Variants

VariantUsageExample
PrimaryMain actions, form submissionsSave, Submit, Create
SecondaryAlternative actionsCancel, Back
OutlineTertiary actions with visible boundaryEdit, View
GhostMinimal emphasis, toolbar actionsClose, Menu items
DestructiveDangerous/irreversible actionsDelete, Remove
LinkInline text links styled as buttonsLearn more

Sizes

SizeHeightPaddingUsage
sm32pxpy-1 px-3Compact UI, tables
default36pxpy-1.5 px-4Standard usage
lg40pxpy-2 px-6Prominent actions
icon36pxp-2Icon-only buttons

States

StateDescription
DefaultNormal interactive state
HoverMouse over the button
FocusKeyboard focus with visible ring
Active/PressedDuring click
DisabledNon-interactive, reduced opacity
LoadingAction in progress with spinner

Icon Usage

Icons can be placed before or after button text:

<Button>
  <PlusIcon className="size-4" />
  Create New
</Button>

<Button>
  Download
  <DownloadIcon className="size-4" />
</Button>

Guidelines

  • Icon size should be 16px (size-4) for default buttons
  • Maintain 8px gap between icon and text
  • Use descriptive icons that reinforce the action

Accessibility

  • Always include accessible label (visible text or aria-label)
  • Disabled buttons should have disabled attribute
  • Loading state should include aria-busy="true"
  • Focus ring must be clearly visible

Do's and Don'ts

Do

  • Use Primary for the main action on a page/dialog
  • Use Destructive for irreversible actions
  • Keep button labels short and action-oriented
  • Show loading state for async actions

Don't

  • Don't use multiple Primary buttons in the same context
  • Don't use Destructive for non-dangerous actions
  • Don't disable buttons without explanation
  • Don't use icon-only buttons without tooltip

Code Example

import { Button } from "@/components/ui/button"
import { Plus, Trash2, Loader2 } from "lucide-react"

// Primary
<Button>Save Changes</Button>

// Secondary
<Button variant="secondary">Cancel</Button>

// Destructive
<Button variant="destructive">
  <Trash2 className="size-4" />
  Delete
</Button>

// Loading
<Button disabled>
  <Loader2 className="size-4 animate-spin" />
  Saving...
</Button>

// Sizes
<Button size="sm">Small</Button>
<Button size="default">Default</Button>
<Button size="lg">Large</Button>