Rost
← All components
component

Button

A 48px button with a label and, if it helps, an icon in front. In four levels of emphasis.

In codeContract: stableGuidance: agreedContract on GitHubFigma 20:14
Primary · Default
Primary · Disabled
Secondary · Default
Secondary · Disabled
Tertiary · Default
Tertiary · Disabled
Borderless · Default
Borderless · Disabled

Hover, press or tab to one to see the other 12 states.

When to use

  • Doing something: save, send, continue, open.
  • Primary for the one thing a screen is really about. One per screen, no more.
  • Secondary for the options next to it, Tertiary when little is at stake, Borderless in busy places where an outline would just be noise.
  • An icon when it helps people get it faster: a back arrow, an external link, a download.

When not to use

  • When the icon is just decoration. Leave it out.
  • When there's no room for the label. That's IconButton, never a Button with its label hidden.
  • Picking between options. That's Toggle or Chip.

Behaviour

type sets how loud it is. state is never something you pass in code: hover, pressed and focus come from :hover, :active and :focus-visible. Disabled is the only one you set yourself. The background fades to opacity/gentle and the label stays readable. In a nav, the page you're on wears the pressed look (aria-current="page"): it reads as chosen, not as broken. The icon sits in a 20px slot (icons-arrow-left in Figma) and takes the label's colour.

Accessibility

  • Element: <button type="button">, type="submit" inside a form, or <a> when it takes you somewhere. A button that navigates is still a link, so it keeps open-in-new-tab and the back button.
  • Name: the label people see. Don't swap it for an aria-label that says something else. The icon is aria-hidden="true".
  • Keyboard: Enter, and Space for buttons.
  • Focus: the focus-ring part, 2px, only on :focus-visible.
  • Disabled: I'd rather use aria-disabled="true" with a short reason nearby than disabled. disabled drops the button out of the tab order and nobody can find out why it doesn't work.

Content

A verb, sentence case, two or three words. "Save changes", not "OK" or "SUBMIT". Say what will happen. An icon has to match the words: an arrow pointing left only on "Back".

Props

PropTypeValuesDefault
iconslot
typeenumBorderless · Primary · Secondary · TertiaryBorderless

States: Default, Hover, Pressed, Focus, Disabled.

Where it's used

Where code differs on purpose

Values

Straight from the contract. Each value sits next to its token, because six tokens here all come out as #3a3a3a and the colour alone can't tell you which one is right.

Never changes

PartPropertyValueToken
rootjustify-contentcenterlayout
rootalign-itemscenterlayout
rootdisplayinline-flexlayout
rootvertical-alignmiddlelayout
rootpositionrelativelayout
rootbackgroundnoneFigma frame size
rootbordernoneFigma frame size
rootfontinheritFigma frame size
roottext-decorationnoneFigma frame size
rootcursorpointerFigma frame size
rootoutlinenoneFigma frame size
rootgap8pxspacing/gap/small
rootheight48pxspacing/size/medium-large
rootborder-radius10000pxspacing/radius/full
labelflex-shrink0layout
labelwhite-spacenowraplayout
labeltext-aligncenterlayout
labelpositionrelativelayout
labelfont-family'General Sans Variable'font-family/base
labelfont-weight500typography/body/font-weight/medium
labelline-height22pxtypography/body/line-height
labelfont-size16pxtypography/body/font-size
labelletter-spacing0pxtypography/body/letter-spacing
icons-arrow-leftdisplayflexlayout
icons-arrow-leftalign-itemscenterlayout
icons-arrow-leftjustify-contentcenterlayout
icons-arrow-leftoverflowcliplayout
icons-arrow-leftflex-shrink0layout
icons-arrow-leftpositionrelativelayout
icons-arrow-leftwidth20pxspacing/size/xsmall
icons-arrow-leftheight20pxspacing/size/xsmall
unionpositionabsolutelayout
unioninset20.84% 16.66% 20.83% 18.4%layout
focus-ringdisplaynonelayout
focus-ringborder-stylesolidno token yet
focus-ringpointer-eventsnoneFigma frame size
backgroundpositionabsolutelayout
backgroundinset0layout
backgroundpointer-eventsnoneFigma frame size

Changes by variant

background.background9
type=Tertiary, state=Hover#060805actions/tertiary/hover/background
type=Tertiary, state=Pressed#454545actions/tertiary/pressed/background
type=Borderless, state=Hover#060805actions/tertiary/hover/background
type=Borderless, state=Pressed#454545actions/tertiary/pressed/background
type=Secondary, state=Default#3a3a3aactions/secondary/regular/default/background
type=Secondary, state=Hover#747573actions/secondary/regular/hover/background
type=Secondary, state=Pressed#999actions/secondary/regular/pressed/background
type=Secondary, state=Disabled#3a3a3aactions/secondary/regular/disabled/background
type=Secondary, state=Focus#3a3a3aactions/secondary/regular/focus/background
background.border-color5
type=Secondary, state=Default#edededactions/secondary/regular/default/outline
type=Secondary, state=Hover#edededactions/secondary/regular/hover/outline
type=Secondary, state=Pressed#edededactions/secondary/regular/pressed/outline
type=Secondary, state=Disabled#edededactions/secondary/regular/disabled/outline
type=Secondary, state=Focus#edededactions/secondary/regular/focus/outline
background.border-radius7
type=Tertiary, state=Hover10000pxspacing/radius/full
type=Tertiary, state=Pressed10000pxspacing/radius/full
type=Secondary, state=Default10000pxspacing/radius/full
type=Secondary, state=Hover10000pxspacing/radius/full
type=Secondary, state=Pressed10000pxspacing/radius/full
type=Secondary, state=Disabled10000pxspacing/radius/full
type=Secondary, state=Focus10000pxspacing/radius/full
background.border-sides5
type=Secondary, state=Defaultleft toplayout
type=Secondary, state=Hoverleft toplayout
type=Secondary, state=Pressedleft toplayout
type=Secondary, state=Disabledleft toplayout
type=Secondary, state=Focusleft toplayout
background.inset9
type=Tertiary, state=Hover0layout
type=Tertiary, state=Pressed0layout
type=Borderless, state=Hover0layout
type=Borderless, state=Pressed0layout
type=Secondary, state=Default0layout
type=Secondary, state=Hover0layout
type=Secondary, state=Pressed0layout
type=Secondary, state=Disabled0layout
type=Secondary, state=Focus0layout
background.opacity9
type=Tertiary, state=Hover0.32opacity/mild
type=Tertiary, state=Pressed0.32opacity/mild
type=Borderless, state=Hover0.32opacity/mild
type=Borderless, state=Pressed0.32opacity/mild
type=Secondary, state=Default0.24opacity/gentle
type=Secondary, state=Hover0.32opacity/mild
type=Secondary, state=Pressed0.32opacity/mild
type=Secondary, state=Disabled0.32opacity/mild
type=Secondary, state=Focus0.24opacity/gentle
background.position9
type=Tertiary, state=Hoverabsolutelayout
type=Tertiary, state=Pressedabsolutelayout
type=Borderless, state=Hoverabsolutelayout
type=Borderless, state=Pressedabsolutelayout
type=Secondary, state=Defaultabsolutelayout
type=Secondary, state=Hoverabsolutelayout
type=Secondary, state=Pressedabsolutelayout
type=Secondary, state=Disabledabsolutelayout
type=Secondary, state=Focusabsolutelayout
focus-ring.border-color4
type=Primary, state=Focus#b6ffdaactions/primary/focus/focus-ring
type=Tertiary, state=Focus#999actions/secondary/regular/focus/focus-ring
type=Borderless, state=Focus#999actions/secondary/regular/focus/focus-ring
type=Secondary, state=Focus#999actions/secondary/regular/focus/focus-ring
focus-ring.border-radius3
type=Primary, state=Focus10000pxspacing/radius/full
type=Tertiary, state=Focus10000pxspacing/radius/full
type=Secondary, state=Focus10000pxspacing/radius/full
focus-ring.border-sides4
type=Primary, state=Focusalllayout
type=Tertiary, state=Focusalllayout
type=Borderless, state=Focusalllayout
type=Secondary, state=Focusalllayout
focus-ring.border-width4
type=Primary, state=Focus2pxspacing/outline/medium
type=Tertiary, state=Focus2pxspacing/outline/medium
type=Borderless, state=Focus2pxspacing/outline/medium
type=Secondary, state=Focus2pxspacing/outline/medium
focus-ring.display4
type=Primary, state=Focusblocklayout
type=Tertiary, state=Focusblocklayout
type=Borderless, state=Focusblocklayout
type=Secondary, state=Focusblocklayout
focus-ring.inset4
type=Primary, state=Focuscalc(-1 * var(--spacing-gap-2xsmall))layout
type=Tertiary, state=Focuscalc(-1 * var(--spacing-gap-2xsmall))layout
type=Borderless, state=Focuscalc(-1 * var(--spacing-gap-2xsmall))layout
type=Secondary, state=Focuscalc(-1 * var(--spacing-gap-2xsmall))layout
focus-ring.position4
type=Primary, state=Focusabsolutelayout
type=Tertiary, state=Focusabsolutelayout
type=Borderless, state=Focusabsolutelayout
type=Secondary, state=Focusabsolutelayout
label.color20
type=Primary, state=Default#060805actions/primary/default/label
type=Primary, state=Hover#060805actions/primary/hover/label
type=Primary, state=Focus#060805actions/primary/focus/label
type=Primary, state=Pressed#060805actions/primary/pressed/label
type=Primary, state=Disabled#060805actions/primary/disabled/label
type=Tertiary, state=Default#d3d9d5actions/tertiary/default/label
type=Tertiary, state=Hover#edededactions/tertiary/hover/label
type=Tertiary, state=Pressed#d3d9d5actions/tertiary/pressed/label
type=Tertiary, state=Disabled#d3d9d5actions/tertiary/disabled/label
type=Tertiary, state=Focus#d3d9d5actions/tertiary/focus/label
type=Borderless, state=Default#d3d9d5actions/tertiary/default/label
type=Borderless, state=Hover#edededactions/tertiary/hover/label
type=Borderless, state=Pressed#d3d9d5actions/tertiary/pressed/label
type=Borderless, state=Disabled#d3d9d5actions/tertiary/disabled/label
type=Borderless, state=Focus#d3d9d5actions/tertiary/focus/label
type=Secondary, state=Default#d3d9d5actions/secondary/regular/default/label
type=Secondary, state=Hover#edededactions/secondary/regular/hover/label
type=Secondary, state=Pressed#d3d9d5actions/secondary/regular/pressed/label
type=Secondary, state=Disabled#d3d9d5actions/secondary/regular/disabled/label
type=Secondary, state=Focus#d3d9d5actions/secondary/regular/focus/label
root.background5
type=Primary, state=Default#00d669actions/primary/default/background
type=Primary, state=Hover#00b450actions/primary/hover/background
type=Primary, state=Focus#00d669actions/primary/focus/background
type=Primary, state=Pressed#00913aactions/primary/pressed/background
type=Primary, state=Disabled#00d669actions/primary/disabled/background
root.box-shadow5
type=Primary, state=Defaultinset var(--spacing-outline-small) var(--spacing-outline-small) 0 0 var(--actions-primary-default-outline)on purpose: Figma's 1px left and top stroke, drawn inside the shape the way Figma draws it. A border would make the button 1px wider. The width and colour are tokens.
type=Primary, state=Hoverinset var(--spacing-outline-small) var(--spacing-outline-small) 0 0 var(--actions-primary-hover-outline)on purpose: Figma's 1px left and top stroke, drawn inside the shape the way Figma draws it. A border would make the button 1px wider. The width and colour are tokens.
type=Primary, state=Focusinset var(--spacing-outline-small) var(--spacing-outline-small) 0 0 var(--actions-primary-focus-outline)on purpose: Figma's 1px left and top stroke, drawn inside the shape the way Figma draws it. A border would make the button 1px wider. The width and colour are tokens.
type=Primary, state=Pressedinset var(--spacing-outline-small) var(--spacing-outline-small) 0 0 var(--actions-primary-pressed-outline)on purpose: Figma's 1px left and top stroke, drawn inside the shape the way Figma draws it. A border would make the button 1px wider. The width and colour are tokens.
type=Primary, state=Disabledinset var(--spacing-outline-small) var(--spacing-outline-small) 0 0 var(--actions-primary-disabled-outline)on purpose: Figma's 1px left and top stroke, drawn inside the shape the way Figma draws it. A border would make the button 1px wider. The width and colour are tokens.
root.cursor4
type=Primary, state=DisableddefaultFigma frame size
type=Tertiary, state=DisableddefaultFigma frame size
type=Borderless, state=DisableddefaultFigma frame size
type=Secondary, state=DisableddefaultFigma frame size
root.opacity4
type=Primary, state=Disabled0.24opacity/gentle
type=Tertiary, state=Disabled0.24opacity/gentle
type=Borderless, state=Disabled0.24opacity/gentle
type=Secondary, state=Disabled0.24opacity/gentle
root.padding5
type=Borderless, state=Default0pxspacing/gap/none
type=Borderless, state=Hover0pxspacing/gap/none
type=Borderless, state=Pressed0pxspacing/gap/none
type=Borderless, state=Disabled0pxspacing/gap/none
type=Borderless, state=Focus0pxspacing/gap/none
root.padding-bottom15
type=Primary, state=Default0pxspacing/gap/none
type=Primary, state=Hover0pxspacing/gap/none
type=Primary, state=Focus0pxspacing/gap/none
type=Primary, state=Pressed0pxspacing/gap/none
type=Primary, state=Disabled0pxspacing/gap/none
type=Tertiary, state=Default0pxspacing/gap/none
type=Tertiary, state=Hover0pxspacing/gap/none
type=Tertiary, state=Pressed0pxspacing/gap/none
type=Tertiary, state=Disabled0pxspacing/gap/none
type=Tertiary, state=Focus0pxspacing/gap/none
type=Secondary, state=Default0pxspacing/gap/none
type=Secondary, state=Hover0pxspacing/gap/none
type=Secondary, state=Pressed0pxspacing/gap/none
type=Secondary, state=Disabled0pxspacing/gap/none
type=Secondary, state=Focus0pxspacing/gap/none
root.padding-left15
type=Primary, state=Default20pxspacing/gap/medium-large
type=Primary, state=Hover20pxspacing/gap/medium-large
type=Primary, state=Focus20pxspacing/gap/medium-large
type=Primary, state=Pressed20pxspacing/gap/medium-large
type=Primary, state=Disabled20pxspacing/gap/medium-large
type=Tertiary, state=Default20pxspacing/gap/medium-large
type=Tertiary, state=Hover20pxspacing/gap/medium-large
type=Tertiary, state=Pressed20pxspacing/gap/medium-large
type=Tertiary, state=Disabled20pxspacing/gap/medium-large
type=Tertiary, state=Focus20pxspacing/gap/medium-large
type=Secondary, state=Default20pxspacing/gap/medium-large
type=Secondary, state=Hover20pxspacing/gap/medium-large
type=Secondary, state=Pressed20pxspacing/gap/medium-large
type=Secondary, state=Disabled20pxspacing/gap/medium-large
type=Secondary, state=Focus20pxspacing/gap/medium-large
root.padding-right15
type=Primary, state=Default20pxspacing/gap/medium-large
type=Primary, state=Hover20pxspacing/gap/medium-large
type=Primary, state=Focus20pxspacing/gap/medium-large
type=Primary, state=Pressed20pxspacing/gap/medium-large
type=Primary, state=Disabled20pxspacing/gap/medium-large
type=Tertiary, state=Default20pxspacing/gap/medium-large
type=Tertiary, state=Hover20pxspacing/gap/medium-large
type=Tertiary, state=Pressed20pxspacing/gap/medium-large
type=Tertiary, state=Disabled20pxspacing/gap/medium-large
type=Tertiary, state=Focus20pxspacing/gap/medium-large
type=Secondary, state=Default20pxspacing/gap/medium-large
type=Secondary, state=Hover20pxspacing/gap/medium-large
type=Secondary, state=Pressed20pxspacing/gap/medium-large
type=Secondary, state=Disabled20pxspacing/gap/medium-large
type=Secondary, state=Focus20pxspacing/gap/medium-large
root.padding-top15
type=Primary, state=Default0pxspacing/gap/none
type=Primary, state=Hover0pxspacing/gap/none
type=Primary, state=Focus0pxspacing/gap/none
type=Primary, state=Pressed0pxspacing/gap/none
type=Primary, state=Disabled0pxspacing/gap/none
type=Tertiary, state=Default0pxspacing/gap/none
type=Tertiary, state=Hover0pxspacing/gap/none
type=Tertiary, state=Pressed0pxspacing/gap/none
type=Tertiary, state=Disabled0pxspacing/gap/none
type=Tertiary, state=Focus0pxspacing/gap/none
type=Secondary, state=Default0pxspacing/gap/none
type=Secondary, state=Hover0pxspacing/gap/none
type=Secondary, state=Pressed0pxspacing/gap/none
type=Secondary, state=Disabled0pxspacing/gap/none
type=Secondary, state=Focus0pxspacing/gap/none