Button
- 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 visually represent themselves as a link. This visual representation is used when the action needs to be in line with other text.
This visual variant does not impact the HTML structure; assistive technologies will still recognize it as a button. Use the Link component if you are 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.
Name | Type | Default | Description |
---|---|---|---|
after | ReactNode | - | Content shown after children. |
before | ReactNode | - | Content shown before the children. |
children | ReactNode | - | The content of the Link. |
color | error primary | primary | Background and foreground colors. |
edge | end start | - | Aligns 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 | boolean | - | If true , a loading indicator will be shown. See SubmitButton for a ready-made component. |
size | small medium large | large | The size of the button when variant is set to "primary" or "secondary". |
variant | link primary secondary tertiary | secondary | Determines the shape of the element (button or text link). |
- 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 loadingconst 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…');