agents/projects/chrome-design-system/assets/component-specs/Buttons_Spec.md
This specification document outlines the mapping, design tokens, styling variants, and interactive states of the Buttons component across Figma, C++ Views, and WebUI (Web Frontend).
The Buttons component is a core interactive control that allows users to trigger actions, execute commands, or submit forms. It supports text labels, optional leading or trailing icons, and multiple levels of visual emphasis.
| Feature | Figma Component | C++ Views (Desktop) | WebUI (Web Frontend) |
|---|---|---|---|
| Component Name | Buttons | views::MdTextButton / views::LabelButton | <cr-button> |
| Source Files | Figma Link: 20268:1070 | ui/views/controls/button/md_text_button.h | |
| ui/views/controls/button/label_button.h | ui/webui/resources/cr_elements/cr_button/cr_button.ts |
| Feature / Variant | Figma Component | C++ Views (Desktop) | WebUI (Web Frontend) |
|---|---|---|---|
| Primary Style | Variant=Primary | ui::ButtonStyle::kProminent | <cr-button class="action-button"> |
| Tonal Style | Variant=Tonal | ui::ButtonStyle::kTonal | <cr-button class="tonal-button"> |
| Outlined Style | Variant=Outlined | ui::ButtonStyle::kDefault | <cr-button> (Default style) |
| Text Style | Variant=Text | ui::ButtonStyle::kText | <cr-button> (Flat style) |
| Leading Icon | Icons=Leading | LabelButton::SetImageModel() | Slot: <slot name="prefix-icon"> |
| Trailing Icon | Icons=Trailing | views::MdTextButtonWithDownArrow or custom LabelButtonImageContainer | Slot: <slot name="suffix-icon"> |
| State | Figma Component | C++ Views (Desktop) | WebUI (Web Frontend) |
|---|---|---|---|
| Default (Normal) | State=Default | Button::ButtonState::STATE_NORMAL | Default state / no modifiers |
| Hovered | State=Hovered | Button::ButtonState::STATE_HOVERED | :hover pseudo-class |
#hoverBackground overlay | |||
| Pressed (Pushed) | State=Pressed | Button::ButtonState::STATE_PRESSED | :active pseudo-class |
<cr-ripple> (Ink ripple) | |||
| Disabled | State=Disabled | Button::ButtonState::STATE_DISABLED | Attribute: <cr-button disabled> |
| Focused | (Commonly represented) | Triggers custom views::FocusRing drawing | :focus / :focus-visible pseudo-classes |
.focus-outline-visible class |
This table tracks how specific design tokens (colors, typography, spacing, and shapes) defined in the Figma design system map directly to C++ Views and WebUI configurations, including cases where hardcoded equivalents or custom fallbacks are utilized.
| Design Attribute | Figma Design Token | C++ Views (Desktop) | WebUI (Web Frontend) |
|---|---|---|---|
| Primary Container Background | --desktop/sys/primary-colors/primary | ||
(#0b57d0) | ui::kColorButtonBackgroundProminent | --color-button-background-prominent | |
| On-Primary Foreground | --desktop/sys/primary-colors/on-primary | ||
(white) | ui::kColorButtonForegroundProminent | --color-button-foreground-prominent | |
| Tonal Container Background | --desktop/sys/container-colors/tonal-container | ||
(#d3e3fd) | ui::kColorButtonBackgroundTonal | --color-button-background-tonal | |
| On-Tonal Foreground | --desktop/sys/container-colors/on-tonal-container | ||
(#041e49) | ui::kColorButtonForegroundTonal | --color-button-foreground-tonal | |
| Border Outline Color | --desktop/sys/outline-colors/tonal-outline | ||
(#a8c7fa) | ui::kColorButtonBorder | --color-button-border | |
| Disabled Container BG | --desktop/sys/state-colors/state-disabled-container | ||
(rgba(31,31,31,0.12)) | ui::kColorButtonBackgroundProminentDisabled | --color-button-background-prominent-disabled | |
| Disabled Foreground | --desktop/sys/state-colors/state-disabled | ||
(rgba(31,31,31,0.38)) | ui::kColorButtonForegroundDisabled | --color-button-foreground-disabled | |
| Hover State Overlay | --desktop/sys/state-colors/state-hover-on-prominent / state-hover-on-subtle | ui::kColorButtonHoverBackgroundText | --cr-hover-background-color / --cr-hover-on-prominent-background-color |
| Font Family | --desktop/font/body | ||
("Google_Sans_Text:Medium") | Native font family resolved by ui::ResourceBundle | Default system font family | |
| Font Weight | --desktop/font_weight/medium | ||
(500 / medium) | MediumWeightForUI() (Returns 500) | font-weight: 500; (Hardcoded in cr_button.css) | |
| Font Size | --desktop/font_size/button | ||
(13px) | gfx::PlatformFont::GetFontSizeDelta(13) | font-size: 13px; (Derived from base text/button settings) | |
| Line Height | --desktop/line_height/button | ||
(20px) | Handled via Typography Provider heights | line-height: 20px; (Default) / 154% (For Prominent style) | |
| Padding (Horizontal) | --desktop/spacing/16 | ||
(16px outer horizontal padding) | DistanceMetric::kDistanceButtonHorizontalPadding | padding: 8px 16px; (Hardcoded in cr_button.css) | |
| Padding (Vertical) | --desktop/spacing/8 | ||
(8px outer vertical padding) | DistanceMetric::kDistanceButtonVerticalPadding | padding: 8px 16px; (Hardcoded in cr_button.css) | |
| Gap (Icon-to-Label) | --desktop/spacing/8 | ||
(8px) | Handled internally in LabelButton::GetImageLabelSpacing() | gap: 8px; (Hardcoded in cr_button.css) | |
| Corner Radius | --desktop/corner-radius/fully-rounded | ||
(999px) | ShapeContextTokens::kButtonRadius (Resolves to fully pill-shaped button) | border-radius: 100px; (Pill style hardcoded in cr_button.css) |
--desktop/corner-radius/fully-rounded which is set to 999px to enforce a safe, pill-shaped edge.border-radius: 100px; inside cr_button.css. While it visually achieves the same pill shape as 999px for standard button heights, it does not use the CSS design token and has a differing hardcoded value.ShapeContextTokens::kButtonRadius which is resolved dynamically by the layout provider. This usually maps to a smaller, specific radius based on standard Material 3 specs (e.g., 8px or 12px depending on context and chrome-specific design rules) rather than a "fully rounded" 999px or 100px pill shape.#d3e3fd (tonal-container) and text is #041e49 (on-tonal-container).kColorSysTonalContainer / --color-button-background-tonal). These colors are dynamically generated at runtime based on the user's active OS/Chrome theme, meaning they will frequently differ from the static #d3e3fd value in Figma.--desktop/font_size/button set to 13px.<cr-button> does not specify an explicit font-size within its cr_button.css stylesheet. Instead, it inherits the text size from its surrounding context or layout host, which can lead to rendering differences (e.g., 12px or 13px) depending on where the button is placed.13px via gfx::PlatformFont::GetFontSizeDelta(13), which is scaled natively according to the operating system's display scale (DPI).--desktop/line_height/button to 20px for all variants.line-height: 20px; as the default fallback in cr_button.css. However, when styled as .action-button (Primary style) or .cancel-button, it overrides this with line-height: 154%; (which scales relative to the inherited font size).--desktop/spacing/16 (16px) for horizontal and --desktop/spacing/8 (8px) for vertical.padding-inline-start is reduced to 12px (--icon-block-padding-small), while padding-inline-end remains 16px (--icon-block-padding-large).padding-inline-start remains 16px, while padding-inline-end is reduced to 12px.
These asymmetric shifts do not exist in the static Figma component."Text" variant (no border, transparent background).ui::ButtonStyle::kText.<cr-button> does not have a built-in class (like .text-button or .flat-button) to automatically remove the border and background. To achieve a text-only button, developers must manually override custom properties inline (e.g., setting --cr-button-border: none; or --cr-button-background-color: transparent;)."Leading and Trailing" variant (two icons on opposite sides of the text label).slot="prefix-icon" and slot="suffix-icon").views::LabelButton / views::MdTextButton does not natively support both leading and trailing icons out-of-the-box. It is architected around a single image model (SetImageModel()), placing one image adjacent to the text. To support a leading icon and a trailing icon together, developers must build a custom LabelButtonImageContainer layout or override the button's internal layout manually.Icons=Trailing and draw the arrow.views::MdTextButtonWithDownArrow, rather than simply setting a property on the standard MdTextButton."Focused" state.views::FocusRing and .focus-outline-visible) to meet accessibility (a11y) standards.SetIsDefault(true)). This dynamically alters the button's theme paint properties and animates the focus border to indicate that pressing "Enter" will trigger it.<cr-button> do not have a built-in "default" visual state tracker; this is handled programmatically (e.g., via HTML form submit events in the web frame).<cr-button> enforces role="button" and tabindex="0". Handles space/enter natively to click.GetViewAccessibility().SetName() to feed accessibility strings. Set accelerators for Cancel (Esc) and Default (Enter) buttons.views::View (Base layout/rendering unit)
└── views::Button (Focusable, clickable base class)
└── views::LabelButton (Adds text & single-image support)
└── views::MdTextButton (Adds Material 3 specification styling)
HTMLElement (Native browser base)
└── LitElement / CrLitElement (Reactive web component base)
└── CrButtonElement (with CrRippleMixin for ink ripples)