Button
A clear, responsive action with quiet secondary states.
pnpm dlx shadcn@latest add @uiarc/buttonLive · 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/buttonAdds 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.
The full library index for assistants is at /llms.txt.