Button

A clear, responsive action with quiet secondary states.

pnpm dlx shadcn@latest add @uiarc/button
Live · keyboard ready
  • Any single action on a page, form, or dialog, such as Save, Continue, or Cancel.
  • Actions whose label changes in place, like Save to Saved, where the width should spring instead of jump.
  • Short async work where a spinner on the button is enough feedback, via loading.
  • Use action-button when the button itself should show pending and success states after an async commit.
  • Use split-button when one default action has two to five close variants.
  • Use hold-to-confirm for destructive actions that need more than a single click.

Installation

Add Button with the shadcn CLI, or copy the source by hand.

pnpm dlx shadcn@latest add @uiarc/button

Adds the component and its local dependencies, and installs motion. First time? Add the @uiarc registry to components.json, or use the full URL:

example.tsx
import { Button } from "@/registry/components/button/button"; export function SaveBar() {  return (    <Button variant="primary" loading={saving} onClick={save}>      Save changes    </Button>  );}

Label that morphs after saving

example.tsx
<Button variant="secondary" loading={saving} onClick={save}>  {saved ? "Saved" : "Save draft"}</Button>

Button

A native button with press feedback and a label that morphs its width when the content changes.

PropTypeDefaultDescription
variant"primary" | "secondary" | "ghost" | "danger""primary"Visual weight. Use one primary action per surface.
size"sm" | "md" | "lg""md"Height and padding.
loadingbooleanfalseShows a spinner, sets aria-busy, and swallows clicks while keeping focus.
...propsButtonHTMLAttributes<HTMLButtonElement>–Forwarded to the underlying button, including ref, disabled, type, and onClick.
EnterorSpace
Activates the button.
  • Renders a native button, so role and focus come for free.
  • Loading uses aria-busy and aria-disabled instead of disabled, so keyboard focus is not lost mid-action.
  • Icon-only buttons need an aria-label.
  • Presses scale to about 0.97 on a snappy spring; icon-sized buttons press slightly deeper.
  • A new label crossfades with a short blur while the width springs to fit.
  • Reduced motion drops the press scale and swaps labels with a plain fade.
  • Size is fixed by the size prop; the button never changes layout by breakpoint, so pick lg for primary touch targets.
  • Hover styles apply only on hover-capable fine pointers, so taps on touch screens do not stick in a hover state.
  • A ResizeObserver measures the label so the width can spring; one per button is cheap, but avoid hundreds in a long list.
  • Label changes animate opacity, transform, and a small blur only, with no layout thrash beyond the width spring.

Notes for AI

Give your coding assistant the Markdown reference instead of screenshots.

  • Default choice for any single action. Use action-button for dense icon toolbars and split-button when one action has close alternatives.
  • Pass a changing label (Save → Saved) as children to get the width morph for free.
  • Wrap in a Radix trigger with asChild; the press scale turns off automatically for popup anchors.
/components/button/markdown

The full library index for assistants is at /llms.txt.