Button
DraftButtons are controls that let users take action, make choices, and move forward.
- Usage
- Specs
- Content
- Status & changelog
Common alternative names
Action, call to action, CTA
Principles
Actionable
A button label indicates what happens when the user taps the button, even if it's just to acknowledge something.
Contextual
Buttons work with other elements on a screen to surface the most important actions the user wants to take in that context.
Incisive
Buttons capture user intent concisely, distilling the action a user wants to take into an inclusive word or phrase.
Anatomy
The most basic setup of a button includes only a single label or icon. Still, a button can also be customized to include a label with a leading icon and a trailing icon. Circle buttons can also support an additional label below the button's container.
Shape
Buttons come in rectangular, circle, square, and pill shapes.
Rect (default)
Rectangular buttons are typically used at fixed widths, 100% and 50% width on mobile, and a variety of widths on the web. Large rectangle buttons are commonly used CTA buttons that move users forward in a flow.
Circle
Circular buttons can include a text label or an icon. An optional label below is available as well. All maintain a center position.
Square
Square buttons, similar to circle buttons, can include a text label or an icon. All maintain a center position.
Pill
Pill buttons are more commonly in line with other content and controls.
Usage
Use buttons to let users take action, make choices, and move forward. Buttons can navigate to other pages while completing an action like purchasing or submitting a form.
Hierarchy
Button hierarchy emphasizes which button is more important in the context so the user can take action immediately.
Buttons use color and contrast to create three levels of emphasis and hierarchy. The buttons with the strongest emphasis are primary, followed by secondary, then tertiary.
| Hierarchy | Emphasis | # per context | Use for |
|---|---|---|---|
| Primary | High | 1 | The most important action to move forward in a flow, acknowledge and dismiss, or finish a task. |
| Secondary | Medium | Many | Most actions are in line with other content. |
| Tertiary | Low | A few | Dismissive actions give users a way out to cancel, do nothing, dismiss, or skip. |
Primary
Use one primary button per context to allow users to take a specific action, move forward in a flow, acknowledge and dismiss, or finish a task.
Use one primary button per context to highlight the action the user will most likely take.
Avoid using multiple primary buttons on a screen.
Secondary
Secondary buttons are the bread and butter of the button world. Lean into them whenever possible. The gray background protection provides higher visibility, making them more accessible than tertiary buttons.
Use secondary buttons inline with list items and other elements.
Avoid using primary buttons in the middle of the page. Use secondary buttons instead. Primary actions usually should be pinned at the bottom.
Tertiary
Tertiary buttons are mainly used for dismissive actions that give users a way out of something, letting them do nothing, dismiss, or skip.
Treat buttons with a dismissive behavior similar to "Cancel" with the tertiary style.
Avoid using secondary-style buttons for dismissive actions.
Destructive buttons
Destructive buttons are actions that permanently cause data loss. Because these actions can not be undone, using button hierarchy is essential to reduce errors. Two levels of destructive buttons are typically used together: secondary destructive and primary destructive.
Provide additional friction to prevent user error
If a flow includes an action that could be destructive, it's important to give users a chance to double-check before it's completed. The initial action should be designed in a way that suggests caution, using a secondary destructive button, and then a final confirmation dialog should appear with a more obvious warning, using a primary destructive button.
Use standard buttons for actions that don't cause data loss.
Don't use destructive actions for actions that don't cause data loss, like logging out or canceling a task.
Best practices
Everything is a button
In principle, try to think of the most actionable elements as buttons. Thinking and building this way ensures we have the right touch target areas and user feedback. It also makes our experiences easier to localize and friendlier for people using screen readers.
Avoid disabled buttons
Disabled buttons can be confusing and frustrating for many users and can be difficult to spot for those with low vision. To make things easier, try to enable the button so users can tap it, and provide an error message if any information is missing or incorrect. If you must use a disabled button, include clarifying text, an error message, or a tooltip to explain why.
Leading icons convey meaning, trailing icons indicate affordance
Use leading icons to reinforce the button label's meaning and trailing icons as an affordance of what will happen when you interact with the button.
Common alternative names: Action, call to action, CTA
Behavior
Touch targets
All button sizes meet the minimum 28px touch target. The default (48px) and large (56px) sizes exceed the recommended 44px minimum for mobile. Use mini (28px) and compact (36px) only in dense desktop UI where touch is not the primary input.
States
Primary
Enabled
Text and icons: color-action-primary-text
Container: color-action-primary
Hover
Text and icons: color-action-primary-text
Container: color-action-primary + 10% white overlay
Focus
Text and icons: color-action-primary-text
Container: color-action-primary
Outline: 3 color-border-focus
Pressed / Mousedown
Text and icons: color-action-primary-text
Container: color-action-primary + 20% white overlay
Active
N/a
Disabled
Text and icons: color-text-disabled
Container: color-background-disabled
Loading
Spinner size matches icon size
Secondary
Enabled
Text and icons: color-text-default
Container: color-action-secondary
Hover
Text and icons: color-text-default
Container: color-action-secondary + 4% black
Focus
Text and icons: color-text-default
Container: color-action-ghost-hover
Outline: 3 color-border-focus
Pressed / Mousedown
Text and icons: color-text-default
Container: color-action-secondary + 8% black overlay
Active
Text and icons: color-action-primary-text
Container: color-action-primary
Disabled
Text and icons: color-text-disabled
Container: color-background-disabled
Loading
Container: color-action-ghost-hover
Loading circle background: color-background-default
Loading circle complete: color-border-focus
Tertiary
Enabled
Text and icons: color-text-default
Container: transparent
Hover
Text and icons: color-text-default
Container: color-action-ghost-hover
Focus
Text and icons: color-text-default
Container: transparent
Outline: 3 color-border-focus
Pressed / Mousedown
Text and icons: color-text-default
Container: 4% black overlay
Disabled
Text and icons: color-text-disabled
Container: transparent
Loading
Spinner: color-text-default
Width
Our buttons come in two versions: Fixed and intrinsic width.
Fixed-width buttons have a width that matches the width of their container minus any space on either side. This is the fullWidth prop.
Intrinsic width buttons are sized according to the length of the text. Both versions support the addition of leading icons, but each version has slight differences in how the icons align.
Fixed-width (fill container)
If you enable icons for these buttons, the leading icon centers with the label, and the trailing icons pin to the end of the button (minus the spacing).
Intrinsic width (hug contents)
The button does not stretch to the container's width for intrinsic width buttons. The width equals the label's length plus spacing on either side. When icons are turned on for these buttons, the leading icon and trailing icons remain 8px from the label on either side.
Pill button min-width
Rounded pill buttons have a minimum width to avoid that almost-circle look when fewer characters are in the label.
min width = button height + 24
Use the minimum width for buttons with shorter label lengths.
Don't use a width smaller than the minimum. This creates buttons that are almost a pill but not quite a circle.
Pill button max-width
Avoid stretching pill buttons to the width of a container. Use a rectangle button if you desire fixed-width behavior.
Use intrinsic width pill buttons which correspond to the length of the label.
Avoid stretching pill buttons to fill the width of a container.
Wrapping and truncation
Fixed width buttons
Fixed-width buttons are configured to wrap to the following line by default, but they can be set to truncate to any number of lines if desired.
Intrinsic width buttons
Pill buttons hug the content inside them (intrinsic width). A pill button will keep growing with the length of the label until it reaches the edge of its layout. Beyond that, the button will start to truncate.
Buttons with longer labels set to intrinsic width have the potential to take over the layout, so it's essential to keep labels concise.
Breakpoints
For fixed-width buttons, follow these breakpoint guidelines.
Narrow
The button scales up in width until the screen reaches 600px wide.
Wide
For screens wider than 600px the Button will be in its original size and aligned to the leading side of the content.
Examples
Narrow
Wide
Related components
- ButtonGroup: Group of mutually exclusive buttons
- ButtonDock: Fixed bottom action bar for primary or secondary actions
- Link: For navigation without an action
- Toggle: For binary on/off states
- SegmentedControl: For switching between views
Props
| Prop | Type | Default | Description |
|---|---|---|---|
kind | 'primary' | 'secondary' | 'tertiary' | 'dangerPrimary' | 'dangerSecondary' | 'dangerTertiary' | 'primary' | Visual style |
size | 'mini' | 'compact' | 'default' | 'large' | 'default' | Controls height and font |
shape | 'default' | 'pill' | 'circle' | 'square' | 'default' | Border radius / dimensions |
isSelected | boolean | false | Toggle state for ButtonGroup |
disabled | boolean | false | Prevents interaction |
isLoading | boolean | false | Shows spinner, disables button |
loadingText | string | Label shown during loading | |
startEnhancer | ReactNode | Icon before label | |
endEnhancer | ReactNode | Icon after label | |
fullWidth | boolean | false | Stretches to 100% width |
as | ElementType | 'button' | Polymorphic root element |
Spacing
| Size | Padding Y | Padding X | Min Height | Icon Size |
|---|---|---|---|---|
| mini | 6px | 8px | 28px | 16px |
| compact | 10px | 12px | 36px | 16px |
| default | 14px | 16px | 48px | 20px |
| large | 16px | 20px | 56px | 24px |
States
| State | Visual | ARIA |
|---|---|---|
| Default | Base background | |
| Hover | One shade darker | |
| Active/Pressed | Two shades darker | |
| Focus | Inset 2px ring | |
| Disabled | 50% opacity | disabled attribute |
| Loading | Spinner + optional text | aria-busy="true" |
| Selected | Active shade background | aria-pressed="true" |
Keyboard
| Key | Action |
|---|---|
Tab | Move focus to/from button |
Enter | Activate button |
Space | Activate button |
Tokens
| Token | Purpose |
|---|---|
--color-action-primary / -hover / -active | Primary kind colors |
--color-action-secondary-* | Secondary kind colors |
--color-action-ghost-* | Tertiary kind colors |
--color-action-destructive-* | Danger kind colors |
--color-border-focus | Focus ring |
--typography-scale-label-*-font-size | Font per size |
--radius-md, --radius-sm, --radius-full | Border radius per shape |
Writing Button Labels
- Use verbs: "Save changes", not "Changes"
- Be specific: "Delete account" instead of just "Delete"
- Stay concise: 1 to 3 words for primary, up to 5 for secondary
- Use sentence case: "Save changes", not "Save Changes"
Loading Text
When isLoading is true, replace the label with a present participle:
- "Save" → "Saving…"
- "Delete" → "Deleting…"
- "Submit" → "Submitting…"
Icon Guidelines
- Icons should reinforce the label, not replace it (except icon-only buttons)
- Use
startEnhancerfor action icons (add, search, download) - Use
endEnhancerfor directional icons (arrow right, external link, chevron)
Related vs Opposite Actions
Related actions share a common goal (e.g., "End ride" / "Unlock"). Use the same hierarchy level.
Opposite actions conflict (e.g., "Cancel order" / "Continue order"). Use different hierarchy levels: primary for the forward action, tertiary for the dismissive action.
Status
Stable: This component is production-ready and covered by semantic versioning.
Changelog
v0.2.0 (2026-04-04)
- Renamed
varianttokind - Renamed
leftIcon/rightIcontostartEnhancer/endEnhancer - Renamed
loadingtoisLoading - Changed sizes from sm/md/lg to mini/compact/default/large
- Added
shapeprop (default, pill, circle, square) - Added
isSelectedprop - Added kinds: tertiary, dangerSecondary, dangerTertiary
- Removed IconButton. Use
Button shape="circle"instead.
v0.1.0 (2026-04-02)
- Initial release