Skip to content

Button

Button is an interactive UI element for users to trigger a response.
Figma logo
  • Buttons come in many shapes and sizes; common (and recommended) use cases are shown in the examples below.
  • Remember to add a type to your buttons.
  • Buttons are generally provided an onClick handler to trigger an action. Consider the Link component if you are simply navigating to a new URL.
  • Limit pages to one primary CTA per page. Secondary or tertiary buttons or links should be used for secondary tasks.
  • Button text should not wrap to multiple lines. Instead, consider shortening the button’s text.

Buttons come in three primary variants: primary, secondary, and tertiary.

  • Each page should contain only one primary CTA
  • Secondary buttons are the default as they are more common
  • Tertiary buttons do not contain a visible outline, but a background appears on hover; they provide the user with a larger tap target than buttons styled as links

Buttons come in three sizes: small, medium, and large.

Buttons can be styled to look like links. Consider the Link component if you are simply navigating to a new URL.

Tertiary buttons are not outlined and can be aligned to text above and below.

Disabled states are available, but are strongly discouraged. Learn about alternative approaches to disabling buttons.

The loading prop can be used to display the button in a loading state. See SubmitButton for a more realistic implementation.

Icons can be added using the before and after props.

React props
NameTypeDefaultDescription
after  ReactNodeContent shown after children.
before  ReactNodeContent shown before the children.
children  ReactNodeThe content of the Link.
color  errorprimaryprimaryBackground and foreground colors.
edge  endstartAligns the visual edge of a button along a specified side. For example, edge="start" aligns the text of a tertiary button to align with content above and below on the left side.
getLoadingText  (() => string)Determines the screen reader accessible text to be displayed when the button is in the loading state.
loading  booleanIf true, a loading indicator will be shown. See SubmitButton for a ready-made component.
size  smallmediumlargelargeThe size of the button when variant is set to "primary" or "secondary".
variant  linkprimarysecondarytertiarysecondaryDetermines the shape of the element (button or text link).

Button was built with accessibility in mind.

  • Consider using the getLoadingText prop to update the button text for screen readers when the button is in a loading state.
  • Avoid using the disabled attribute as this is confusing to users whether or not they are using assistive technologies.
  • Our color palette was chosen to meet our standards for color contrast ratio.

Here are some basic dos and don'ts for writing buttons.

  • Focus on the action that the user is taking: basically, use a verb
  • Whenever possible, match the action in the CTA to the main heading
  • Use conditional copy when appropriate (e.g. “Withdraw $100.00”)
  • Use sentence case (“Write it like this” and “Don’t Write It Like This”)
  • Don’t preview the next step (“Next select your benefits”)
  • Don’t use multiple actions (wherever possible)
  • Don’t use “Go to” and similar formulations (like “Show x”) for buttons
    • Use a specific action or in-line link instead
  • Don’t use “See” and “View” because they’re not inclusive
    • Some alternatives are: show, read, learn
  • Don’t use icons
    • Exception: for third-party buttons related to Google, include a logo
  • Don’t use end punctuation
  • Don’t use ampersands—use “and” if absolutely necessary
  • Primary CTA: Continue
  • Secondary CTA: Cancel
  • Primary CTA: Continue
  • Secondary CTA: Back
  • Primary CTA: Submit
  • Secondary CTA: Back
  • Primary CTA: Delete [account]; Cancel [account]
  • Secondary CTA: Don't delete; Don't cancel

The following testing snippet(s) offer suggestions for testing the component using React Testing Library with occasional help from Jest.

render(<Button>Save</Button>);
const button = screen.getByRole('button', {
name: 'Save',
});
expect(button).not.toBeDisabled();
userEvent.click(button);
// Testing loading
const onClick = jest.fn();
render(
<Button loading onClick={onClick}>
Save
</Button>,
);
const button = screen.getByRole('button', {
name: /Save/,
});
userEvent.click(button);
expect(button).toBeDisabled();
expect(onClick).not.toHaveBeenCalled();
expect(button).toHaveTextContent('Loading…');