Button

Trigger an action or submit a form. The main action is ink; brand, quieter, and destructive variants step around it.

Fig. 1 Seven variants. Press one with a pointer and it gives a little; keyboard presses donโ€™t move.

When to use it

Use a button for anything that does something: saving, sending, opening a dialog. If it takes people somewhere else, itโ€™s a link, even when it looks like a button.

Give each view one primary action, the darkest thing on it. Put the alternatives beside it as secondary, outline, or ghost buttons, and keep destructive for actions that delete or remove.

Do

One primary action leads; Cancel steps back as secondary.

Donโ€™t

Three primary buttons compete, and nothing says which one to press.

Fig. 2 The same footer, weighted two ways.

Sizes

The default is 32px high, with 13px label text. Use the small sizes in dense toolbars and table rows, and large where a touch target matters.

Fig. 3 Four text sizes, from extra small to large.

Icons

Primary, brand, and destructive buttons are text only; an icon on one signals a state, such as pending or done. Quieter buttons may lead with an icon when it helps people recognize the action.

Icon-only buttons need an accessible label and a Tooltip. ButtonIcon crossfades between two icons in a fixed slot, such as saved and unsaved:

Press to try the action.
Fig. 4 Save and unsave. The icon crossfades in 150ms; reduced motion shortens it to 100ms.
save-button.tsx

Install Tooltip alongside it, and place TooltipProvider once around your app:

Install Tooltip

How it behaves

It defaults to type="button", so it never submits a form by accident; set type="submit" inside forms. Native props, ref, and events are forwarded, and render composes it into links and triggers.

Disabled buttons use native disabled semantics. Pointer presses scale the button to 96%; keyboard presses and reduced motion skip it, and motion={false} turns it off.

Button props
PropValuesDefault
variantdefault ยท brand ยท secondary ยท outline ยท ghost ยท destructive ยท linkdefault
sizexs ยท sm ยท default ยท lg ยท icon-xs ยท icon-sm ยท icon ยท icon-lgdefault
motiontrue ยท falsetrue
typebutton ยท submit ยท resetbutton

Build it

Add it with the shadcn CLI:

Terminal

Every variant in one place:

button-variants.tsx

The full source is yours to edit once installed:

button.tsx