Buttons perform actions. One component covers both standard buttons and icon-only buttons, and six variants set how much emphasis a button carries.
Anatomy
Section titled “Anatomy”-
Container the clickable shape that houses icon and/or label. -
Label (optional) communicates the action (standard buttons only). -
Leading icon (optional) appears before the label. -
Trailing icon (optional) appears after the label.
When to use
Section titled “When to use”Use a button when activating it changes something: submitting a form, creating a record, opening or closing a panel, running a command, or acting on an object in a row or toolbar.
Use a Link when activating it takes the reader somewhere and changes nothing. For an on/off state use a Toggle; for filtering and selection use a Sticker; when the action is one of several related choices, use a Dropdown Menu.
A button that navigates still announces itself as a button
Section titled “A button that navigates still announces itself as a button”to changes what Button renders. A relative path renders a react-router-dom
link; an absolute https:// URL renders an anchor that opens in a new tab, and
target overrides that.
So the button-or-link decision is about how the destination should look and
announce itself, not about which component can navigate. A button that navigates
still reads as a button to a screen reader, which is why to suits actions that
happen to have a URL, like “Open dashboard”, rather than links inside prose.
Variants
Section titled “Variants”- primary The page's main action. Use one primary action per view or section.
- basic △ General actions with regular emphasis.
- outline △ Secondary actions that need visual affordance without heavy emphasis.
- text Lowest emphasis; use when contextual, inline, or when visual noise must be minimal.
- inverse For dark or colored surfaces where other variants would not meet contrast or feel too heavy.
- danger ▲ For destructive or high-risk actions (delete, remove, reset). Always confirm or provide undo.
These six are in emphasis order, loudest first: primary, basic, outline,
text, inverse, danger. The props table lists them in the order the type
declares them, which carries no meaning.
Use inverse on a dark or colored surface, and onSecondaryBackground when a
variant needs adjusting for a secondary background it was not drawn against.
Use one primary button per view
Section titled “Use one primary button per view”A primary marks the single most important action available. Two of them in one
view cancel each other out, because emphasis is relative: the reader cannot tell
which one the screen is asking for. Pair a primary with outline or basic
for the actions beside it, and drop to text inline or in dense areas.
Placement carries emphasis too. A primary in a position the eye reaches last
does not read as the main action however it is styled.
Reserve the danger variant for what it destroys
Section titled “Reserve the danger variant for what it destroys”danger is red fill, and red spends attention the rest of the page then cannot
use. Keep it for outcomes that actually destroy something, and pair it with text
naming the consequence.
Behavior
Section titled “Behavior”Let an async handler own the pending state
Section titled “Let an async handler own the pending state”isPending shows a spinner and disables the button, and it also fires on its own
when onClick returns a promise, clearing once that promise settles. An async
handler therefore gets pending state without being asked, so setting isPending
by hand as well can leave the button disabled after the promise resolves.
Set the button type explicitly inside a form
Section titled “Set the button type explicitly inside a form”type’s own description records why: many existing call sites depend on a
button defaulting to submit, so the default was never changed to button.
Inside a form, a button meant only to open a panel will submit that form unless
you set type="button".
Accessibility
Section titled “Accessibility”Name every icon button
Section titled “Name every icon button”A standard button takes its accessible name from its visible text. An icon button
has no text, so without aria-label it reaches a screen reader as an unnamed
button. Name it for the action rather than the glyph: aria-label="Close", not
aria-label="X icon". Pair it with width="icon", which sizes the button square
to its own height.
Activation works with both Enter and Space. When you disable a button, prefer
aria-disabled over removing it from the tab order, so the reason for the
disabled state can still be reached.
Content
Section titled “Content”Start the label with a verb, and name the object
Section titled “Start the label with a verb, and name the object”A button label is the action it performs: “Create invoice”, “Download CSV”. Buttons are read out of context, in a toolbar or a row of icons or a screen reader’s list of elements, so a label that leans on the text beside it has no meaning where it is needed most.
A danger button names the thing it destroys. “Delete file” is recoverable
knowledge at the moment of clicking; “Remove” is not.
Capitalization, punctuation and the rules that apply to every label are on Writing.
| Name | Type |
|---|---|
variant |
Visual style of the button.
|
isPending |
Shows a loading spinner and disables the button. Also triggers automatically when |
prefixIcon |
Icon rendered to the left of the button label. Import from |
prefixIconType |
Controls how the prefix icon inherits sizing.
|
suffixIcon |
Icon rendered to the right of the button label. Import from |
size |
Height and typography scale of the button. |
to |
Changes the button into a link. Pass a relative path to use |
target |
Overrides the target of the link if |
type |
Note: we may want to default this to ‘button’ in the future, but many instances of this Button component in dashboard currently rely on the default ‘submit’ behavior that occurs when using this in redux-form so we’ll have to comb through and manually add the type=‘submit’ prop. |
width |
Controls the width of the button.
|
onClick |
|
onSecondaryBackground |
In some cases we render a button on a secondary background, which needs an adjustment for certain variants. |
hovered |
Visual state override. Forces the |
focused |
Visual state override. Forces the |
active |
Visual state override. Forces the |
mixed |
Visual state override. Forces the |
ComponentPropsWithoutRef<‘button’>.Was this page helpful?