Components · Actions

Button

A button triggers an action or takes the user to another page. It lets the user make a choice with a single tap. Use a mix of styles on one page to point at the main action and still offer the alternatives.

Tokens, sizes, measurements, states and requirements. Values come from the live token package and from Figma: Button, Icon buttons, Button dot & badges.

Design Tokens

Resolved from the live token package.

Variant · partWhereTokenValue

Open points: Figma sets ss02 and ss03 on label-lg and label-sm but not on label-md (Small): the CSS follows Figma, confirm that is meant. Disabled Primary inverted and Accent were read from the screenshot (grey surface-disabled fill). Figma uses both text-primary-inverted and text-action-primary-inverted for the white of the badge number: the CSS uses the action token. The badge pill uses a literal 100px radius. The toggle icon button has no focus or disabled state in Figma: disabled uses text-disabled, because icon/disabled (#939595) has no token.


Sizes

Heights and type per size and breakpoint. The table is generated from the same numbers the Breakpoint toggle previews.

SizeHeightPaddingLabel insetIconLabel style

Icon-only buttons are squares: width equals height (56 / 48 / 40 / 32px on desktop, 48 / 40 / 32 / 32px on mobile). The 1px frame of Secondary, System and their inverted versions is drawn inside the box, so it never changes the size: Primary and Secondary of the same size are equally wide. The tablet range (640 to 768px) uses the Mobile values.

Badge sizes

Number badge: a pill, as high as it is wide for one digit and wider for two or “99+”. Offsets are from the top and right edge of the button. Same numbers for a button with a label and an icon-only button, except XSmall icon only (2px).

Size · breakpointNumber: offsetHeightSide paddingDigitsDot: offset

The badge is surface-danger-default with a white number (text-action-primary-inverted), uppercase, 600. The dot is a 6px circle in the same color.

Icon buttons

VersionBoxIcon
Toggle icon, Large24px24px
Toggle icon, Small20px20px
Close24px (2px padding)20px

Close is 24px in Figma, below the usual 44px touch target, and Figma has no larger hit-area version. It meets the WCAG 2.2 minimum (24px).


Measurements

Dimensions

The padding of each size: the space between the edge of the button and its content. The label has an extra inset on top of it (see the table). The numbers are read from the component.

Breakpoint
A Secondary button at 2× size. Change the Breakpoint to see the mobile values.
AttributeLargeMediumSmallXSmall
Height, desktop56px48px40px32px
Height, mobile48px40px32px32px
Padding left and right, desktop16px12px8px6px
Padding left and right, mobile12px8px4px6px
Label inset, left and right, desktop8px8px8px4px
Label inset, left and right, mobile8px8px6px4px
Icon24px24px24px20px
Padding above and belowNone: the height is fixed and the content is centredNoneNoneNone
Frame1px, inside the box1px, inside the box1px, inside the box1px, inside the box
Focus ring2px line, 2px gap, outside the box2px line, 2px gap2px line, 2px gap2px line, 2px gap

An icon-only button has no padding: it is a square the size of its height, with the icon centred. The icon button has no padding either (Close has 2px).

Spacing

The padding and the label inset as spacing tokens.

PartValue
Padding, Large desktopspace-16
Padding, Large mobile and Medium desktopspace-12
Padding, Medium mobile and Small desktopspace-8
Padding, Small mobilespace-4
Padding, XSmall6px: literal, no spacing token
Label insetspace-8 (Large, Medium, Small desktop), space-4 (XSmall); Small mobile 6px: literal, no spacing token

States

Button

Every state for every variant. Hover and focus are forced on this page with data-state so they show at the same time; in your code they come from :hover and the keyboard focus rule. The buttons are live (the disabled ones do not respond).

What each state means

StateDescription
EnabledThe standard state of a button: it is available for interaction and is not currently selected. It includes Hover and Focus of the button type.
HoverShown when the user hovers the cursor over the button, to show that the component is interactive.
FocusThe visual style shown when the button is reached with the keyboard (often with Tab). It shows that the button is ready to be activated. It is a blue outline (border-focus), so users can move through the interface without a mouse.
DisabledA disabled button prevents interaction: hover, focus and click. It is not focusable, so Tab skips it. Screen readers may still announce it as unavailable when the user browses the page. Do not associate a tooltip with a disabled button.
SelectedUsed by the System button in some cases. A selected button has been actively chosen, toggled on, or is the item currently in focus within a group of options. It shows which option is active and confirms that the user’s action was registered.
Breakpoint
Size
VariantEnabledHoverFocusDisabled

Hover: Primary, Destructive and Accent get a surface-opacity-white-20 layer on top of their color, Primary inverted a surface-opacity-black-12 layer. Secondary and Blank get surface-opacity-black-05, the inverted ones surface-opacity-white-20. System hover and System selected hover are the same: a surface-opacity-black-12 surface and a border-hover frame. The focus ring is a 2px border-focus line with a 2px gap, drawn outside the button. Disabled: Secondary, Secondary inverted and System keep a frame in border-disabled with no fill; Blank has neither; the others get surface-disabled.

Toggle icons

Eight icons. Each has Enabled, Hover, Selected and Selected hover, in Large (24px) and Small (20px).

Size

Hover changes the icon color to text-action-primary-hover; there is no surface. Selected hover is the filled icon in that color. Figma has no focus or disabled state for these icons: focus follows the button rule, disabled uses text-disabled. The “cancel” icon is always filled.

Close

VersionEnabledHoverFocusDisabled

Figma only defines Enabled and Hover for Close. Focus follows the shared rule; disabled is not defined and is not used for a close control.


Typography

SizeTypeMobile (below 769px)Desktop (769px+)Font features
Largelabel-lg16/16, 0.32px18/18, 0.18pxss02, ss03
Mediumlabel-lg16/16, 0.32px18/18, 0.18pxss02, ss03
Smalllabel-md14/14, 0.42px16/16, 0.48pxNone
XSmalllabel-sm12/12, 0.48px14/14, 0.56pxss02, ss03

Breuer Condensed, weight 600 (Figma bold 700 − 100), uppercase through CSS, so write the label in sentence case in the HTML. The badge number is 12/12 (Large and Medium mobile) or 14/14 (desktop), and 10/10 in Small and XSmall; see the badge sizes under Sizes.


Structure

Elements

ElementClassNotes
ButtonbtnA button for actions, an a for navigation.
Labelbtn__labelAlways wrap the label in it: it carries the label inset. Without it the text sits too close to the edge.
Iconbtn__iconMaterial Symbols, aria-hidden="true".
Badge numberbtn__badgeTop right corner, aria-hidden="true".
Badge dotbtn__dot6px circle, aria-hidden="true".
Icon buttonicon-btn, icon-btn--sm, icon-btn--filledA single icon that is a control. aria-pressed gives the filled icon.
Closeicon-btn icon-btn--close, icon-btn--close-inverted24px box, 20px icon.

Types

ClassUse
btn--primary, btn--primary-invertedMain call to action. Inverted: the same role, where the standard variant lacks contrast.
btn--secondary, btn--secondary-invertedSecond action, with a frame.
btn--blank, btn--blank-invertedThe quietest action, no fill and no frame.
btn--destructiveRemoves something.
btn--accentBrand-colored call to action.
btn--systemA toggle in a group of buttons, with aria-pressed.
btn--lg, btn--md, btn--sm, btn--xsSize. Each sets every --btn-* property, in the mobile block and again from 769px.
btn--iconIcon only: a square, needs an aria-label.

Width

A button hugs its content. An icon-only button is a square. Full width comes from the page layout, not from a modifier.


Motion

PropertyDurationEasing
Hover layer: opacity of ::beforeduration-fast-2 (100ms)ease-standard
Focus ring: outline-colorduration-fast-2ease-standard
Frame: box-shadow (System hover frame)duration-fast-2ease-standard

Figma calls this transition “Dissolve”: a custom bezier .35, 0, .35, 1 over 100ms, which is ease-standard. Under prefers-reduced-motion: reduce the transition is turned off.


Behavior

InputResult
Click, Enter, SpaceRuns the action. Use <button> for actions and <a class="btn …"> for navigation.
Tab / Shift+TabMoves between buttons. The focus ring shows only when body.keyboard-nav is set (on Tab, removed on mousedown and touchstart), the same as the form controls.
DisabledUse the disabled attribute. It is not focusable and has no hover. Say why in nearby text when the reason is not obvious.
System selectedSet aria-pressed="true". It is a toggle, so it must not be used for page navigation.
Icon onlyAdd aria-label, and hide the icon with aria-hidden="true".
LabelUppercase through CSS, so write it in sentence case in the HTML. Keep it short and start with a verb.
Icon only tooltipAlways with a tooltip, shown after a 300ms hover delay (design guidance). Open point: the shared tooltip (components/js/tooltip.js) has no hover delay yet, so it appears at once. Never on a disabled button.

Accessibility Requirements

TopicRequirement
ElementA native <button type="button"> for an action, an <a class="btn …"> for navigation. Never a div with a click handler.
NameA visible label, or an aria-label on an icon-only button. A badge is aria-hidden="true": put the count in the aria-label.
Focus2px ring border-focus with a 2px gap, on keyboard use (WCAG 2.4.7, 1.4.11). It is set with body.keyboard-nav, never :focus-visible.
StateSystem selected is aria-pressed. A disabled button uses the disabled attribute.
Target sizeThe smallest button is 32px high; Close is 24px, which meets WCAG 2.5.8 (24px) but is below the usual 44px touch target.
ContrastChoose standard or inverted variants by context, visibility and contrast, not by background color alone. Disabled tokens are exempt from contrast requirements.