Design System


Twilio's Button component

yarn add @twilio-paste/button


About buttons#

A button communicates that users can trigger an action. Places you’d use a button include:

  • Submitting a form
  • Closing a modal
  • Moving to the next step in a flow

A button can contain an icon and/or text. See Composing a button below for more detailed guidelines.

TL;DR If pressing the trigger results in a URL change, or that resultant page makes sense as a whole new browser tab use an Anchor element. Everything else is a Button.

It may not be immediately obvious but the semantic distinction between an anchor and button HTML element is extremely important to learn. Without realising it the decision can cause significant usability problems due to the in-built behaviours, interactions and expectations that come with each.

For example, an anchor element will perform its action when clicked and when the enter key is pressed. A button element will perform its action when clicked and when the enter and spacebar keys are pressed. When holding the control or command key an anchor will open a new browser tab, a button will not.

You should:

  • Use an Anchor when you are navigating the user to a new page or place on the page
  • Use a Button when the user is performing an action. An action always happens on the same page as the trigger

If you need to link to content, you can use our Anchor component.


For accessibility, the distinction becomes even more important, especially for those who are using Assistive Technology (A.T.) such as screen readers and dictation software. Here are some quick tips:

  • Correctly choosing between an anchor or button element will help inform A.T. users what will happen next. Will I be taken to an entirely new page or will something happen on the current page?
  • Choose button text that clearly describes the action that is about to happen
  • Don’t repeat the same button text on the same page. Try not to have 20 “edit” buttons, add clarifying text, even if it’s visually hidden, to fully describe the action. E.g. “edit home address”, “add new phone number”
  • Don’t communicate with color alone. When choosing a destructive button, make sure the button text also indicates the action is destructive
  • Use anchors that look like buttons sparingly. Voice dictation users may encounter issues when trying to activate them. A user may say, “Click the read more button”, but the dictation software won’t respond since it can’t tell what the anchor looks like visually. Use an alternative where possible, such as an anchor with an icon or with a larger font size.


Primary button#

Use a primary button to indicate the most prominent action a customer would make on a screen. It should be a safe and if possible, reversible action without much cost.

Try to use only one primary button on a screen. Using multiple might be distracting.

Secondary button#

The secondary button is the most frequently used button.

Use a secondary button to indicate an action that should be easy for a customer to make but isn’t the most prominent on a screen. It should be a safe and if possible, reversible action without much cost.

Destructive button#

A destructive button indicates a destructive action, such as “Delete” or “Remove”, that might be difficult to reverse. If possible, give users the ability to undo the action, or at least, confirm the action.

Icon-only button#

Use icon-only buttons sparingly.

They should be used only in compact UI situations. Use an icon that can only convey a single action.

Use link-style buttons when other types of buttons may be too distracting.

Hot accessibility tip

To reiterate, be mindful when choosing this variant as dictation software users may experience usability issues. Read the guidelines first.

Small button#

Use small buttons sparingly, only when needed for vertical density. Guidelines for using variants in small buttons are the same as in their default size.



Use the loading state if the action doesn’t happen instantly. The button is also disabled in this state.

However, the loading state may make an action appear to take longer than it does and doesn’t communicate what’s preventing the action from completing. Use it when you can’t move the user to the next state.


Use the disabled state sparingly.

The customer shouldn't have to guess why a button is disabled. It should be immediately obvious to the customer why a button might be disabled (e.g., if it follows a single empty text field). Otherwise, show the button in its default state, then provide helpful error text after it's pressed.

Composing a button#

In most cases, you’ll use a text-only button.

Button text should:

  • Use sentence case (“Log in”, not “Log In”)
  • Clearly indicate what’ll happen when a user presses it.
  • Start with a verb, except for a common action like “Done.”
  • Be concise without sacrificing clarity and user confidence.

Pair text with an icon only if the icon clarifies the meaning of the button. Use no more than one icon before text and one icon after text.

When to use a button#

Use a button to indicate that users can trigger an action.

In general, align buttons to the direction of the text (e.g., left-aligned in English) for easy scannability.

When moving customers through a sequence, place the primary button in the direction of the movement (e.g., a “Next” button goes on the right in an English-language flow).


Prioritize actions on a screen. Only one primary button should be used on each screen so users are clear about what the intended action is.


Don’t use many primary buttons on a screen, which may distract users.


Use the right variant to communicate meaning and hierarchy.


Don’t use a button variant for an action it’s not intended for.


Write button text that is clear, starts with a verb, and helps users confidently trigger an action.


Don’t use product or brand icons in buttons since they don’t communicate action.

Usage Guide#



yarn add @twilio-paste/button


import {Button} from '@twilio-paste/button';
<Button variant="secondary" size="small" onClick={() => {}}>


type?stringIf the button is inside a <form>: use 'submit'. Otherwise use 'button' (default).'button'
as?stringThe HTML tag to replace the default <button> tag.'button'
href?stringA URL to route to. Must use as="a" for this prop to work.null
variant?ButtonVariants'primary', 'secondary', 'destructive', 'destructive_link', 'link', 'reset''primary'
size?ButtonSizes'default', 'small', 'icon', 'reset''default'
fullWidthbooleanSets the button width to 100% of the parent container.false
disabled?booleanPrevent actions from firing on this buttonfalse
loading?booleanPrevent actions and show a loading spinnerfalse
onClick?(event: React.MouseEvent<HTMLElement>)null
onMouseDown?(event: React.MouseEvent<HTMLElement>)null
onMouseUp?(event: React.MouseEvent<HTMLElement>)null
onMouseEnter?(event: React.MouseEvent<HTMLElement>)null
onMouseLeave?(event: React.MouseEvent<HTMLElement>)null
onFocus?(event: React.FocusEvent<HTMLElement>)null
onBlur?(event: React.FocusEvent<HTMLElement>)null
aria-expanded?booleanA11y: For accordionsnull
aria-haspopup?{'true', 'dialog', 'menu'}A11y: For modals and menusnull
aria-controls?stringA11y: For modals and menusnull
data-test?stringTo detect the element to run tests against.null

Change Log

All notable changes to this project will be documented in this file. See Conventional Commits for commit guidelines.

1.1.32 (2020-04-02)

Note: Version bump only for package @twilio-paste/button

1.1.31 (2020-03-28)

Note: Version bump only for package @twilio-paste/button

1.1.30 (2020-03-24)

Bug Fixes#

  • button: switch from theme-tokens to theme package dep (d9441c2)

1.1.29 (2020-03-20)

Note: Version bump only for package @twilio-paste/button

1.1.28 (2020-03-17)

Note: Version bump only for package @twilio-paste/button

1.1.27 (2020-03-17)

Note: Version bump only for package @twilio-paste/button

1.1.26 (2020-03-11)

Note: Version bump only for package @twilio-paste/button

1.1.25 (2020-03-06)

Bug Fixes#

  • add missing transitive peerDep on '@styled-system/css' (fdbb813)

1.1.24 (2020-03-04)

Bug Fixes#

  • button: change borders to box-shadow (689061d)

1.1.23 (2020-03-02)

Note: Version bump only for package @twilio-paste/button

1.1.22 (2020-03-02)

Note: Version bump only for package @twilio-paste/button

1.1.21 (2020-02-28)

Note: Version bump only for package @twilio-paste/button

1.1.20 (2020-02-26)

Bug Fixes#

  • package dependencies and deprecation warnings (#334) (0e88338)

1.1.19 (2020-02-21)

Note: Version bump only for package @twilio-paste/button

1.1.18 (2020-02-20)

Note: Version bump only for package @twilio-paste/button

1.1.17 (2020-02-19)

Note: Version bump only for package @twilio-paste/button

1.1.16 (2020-02-18)

Note: Version bump only for package @twilio-paste/button

1.1.15 (2020-02-14)

Bug Fixes#

  • button: add missing peer deps (38416d8)

1.1.14 (2020-02-13)

Note: Version bump only for package @twilio-paste/button

1.1.13 (2020-02-11)

Note: Version bump only for package @twilio-paste/button

1.1.12 (2020-02-11)

Note: Version bump only for package @twilio-paste/button

1.1.11 (2020-02-11)

Note: Version bump only for package @twilio-paste/button

1.1.10 (2020-02-07)

Note: Version bump only for package @twilio-paste/button

1.1.9 (2020-02-03)

Note: Version bump only for package @twilio-paste/button

1.1.8 (2020-01-27)

Note: Version bump only for package @twilio-paste/button

1.1.7 (2020-01-25)

Note: Version bump only for package @twilio-paste/button

1.1.6 (2020-01-24)

Bug Fixes#

1.1.5 (2020-01-17)

Note: Version bump only for package @twilio-paste/button

1.1.4 (2019-12-20)

Note: Version bump only for package @twilio-paste/button

1.1.3 (2019-12-19)

Note: Version bump only for package @twilio-paste/button

1.1.2 (2019-12-05)

Note: Version bump only for package @twilio-paste/button

1.1.1 (2019-11-27)

Bug Fixes#

  • button: defensively set hover/focus/active styles from legacy globals (#205) (2a9ce57)

1.1.0 (2019-11-20)

Bug Fixes#

  • remap console semibold to medium font weight (#195) (c01f6b3)


  • icons: make decorative required + icon docs (#165) (15ccbc2)

1.0.2 (2019-11-18)

Bug Fixes#

  • correct button heights add new default icon size (#186) (2e54478)
  • design-tokens: update some blues, reds, and focus shadow (#185) (98d70cc)
  • update destructive button styles to be filled (#189) (c29b7ca)

1.0.1 (2019-11-12)

Note: Version bump only for package @twilio-paste/button

1.0.0 (2019-11-11)

Bug Fixes#

  • button: add font-weight semibold to small buttons (#166) (582245b)
  • website: update button docs with loading and icon states (#167) (7380889)


  • icons: delete old icons, add new streamline icons (#129) (571791d)
  • typography: heading component (#149) (4e033e6)
  • enable theme switching on the docsite (#124) (df797e5)


  • icons: removed all the inherited icons since we're moving to a new system

  • chore(icons): update icon list for storybook

  • fix(spinner): use new icon

  • fix(storybook): use new icon for story

  • fix(story): button icons should be 24px

  • fix: adjust icon size tokens

  • feat: add iconSizes as separate key in theme-tokens

  • feat(icons): icons package to use tokens and update icons

  • fix(spinner): update to use tokens and new icons

  • fix(button): use correct spinner size

  • fix(icons): major icons package fixes

  • huge overhaul to build process
  • now uses rollup
  • builds into cjs and esm directories
  • made the package publishable to npm
  • moved svg folder out of src, now src only holds react stuff
  • updated scripts to use new paths and cleaned up the code
  • programmatically generates rollup config from the icon-list command
  • chore: add new icons dist folders to gitignore

  • fix: spinner and button icon usage

  • feat(icons): add rollup icon list cache file

  • fix(core-bundle): sort packages for consistent builds

  • chore: use esm instead of es in rollup for correctness

  • chore: yarn.lock

  • fix(spinner): lint error

  • chore(icons): move rollup icon list

  • chore(spinner): use types package in story

  • fix(spinner): swap out destructured props for explicit props

0.3.1 (2019-10-31)

Note: Version bump only for package @twilio-paste/button

0.3.0 (2019-10-29)

Bug Fixes#

  • button: border-color should transition with background-color (#130) (fda61ba)
  • remove the underline from button states (#147) (70d4c15), closes #54


0.2.1 (2019-09-16)

Bug Fixes#

  • button: adding some polish (#67) (2644657)
  • button: adjust primary, secondary, desctructive styles (#72) (670faef)

0.2.0 (2019-08-15)

Bug Fixes#



If you need support, please open a new issue in our GitHub repository. Please try to provide as much detail as possible in your issue.


The Paste design system is open source and contributions are welcome. Check out the project on GitHub to learn more about contributing.

Copyright © 2020 Twilio, Inc.