agents/projects/chrome-design-system/assets/component-specs/IconButton_Spec.md
This specification document outlines the mapping, design tokens, styling variants, and interactive states of the IconButton component across Figma, C++ Views, and WebUI (Web Frontend).
The IconButton component is a compact, circular interactive element containing a single vector icon. It is designed to trigger specialized or high-frequency secondary actions within toolbars, cards, tables, or header bars. It does not display a text label, relying on optical visual clarity and accessibility labels to communicate intent.
| Feature | Figma Component | C++ Views (Desktop) | WebUI (Web Frontend) |
|---|---|---|---|
| Component Name | IconButton | views::ImageButton (via CreateIconButton) | <cr-icon-button> |
| Source Files | Figma Link: 20268:1205 | ui/views/controls/button/image_button.h | ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.ts |
| Feature / Variant | Figma Component | C++ Views (Desktop) | WebUI (Web Frontend) |
|---|---|---|---|
| Size: 16dp | size=16dp | MaterialIconStyle::kSmall | CSS: --cr-icon-button-icon-size: 16px; |
--cr-icon-button-size: 28px; | |||
| Size: 20dp | size=20dp (Default) | MaterialIconStyle::kLarge | CSS: --cr-icon-button-icon-size: 20px; |
--cr-icon-button-size: 32px; (Default) |
| State | Figma Component | C++ Views (Desktop) | WebUI (Web Frontend) |
|---|---|---|---|
| Default (Normal) | state=Default | Button::ButtonState::STATE_NORMAL | Default hover-free state |
| Hovered | state=Hovered | Button::ButtonState::STATE_HOVERED | :hover:not([disabled]) pseudo-class |
| Pressed | state=Pressed | Button::ButtonState::STATE_PRESSED | :active pseudo-class with <cr-ripple> |
| Disabled | state=Disabled | Button::ButtonState::STATE_DISABLED | Attribute: <cr-icon-button disabled> |
| Focused | (Commonly represented) | Triggers custom views::FocusRing drawing | :focus-visible:focus pseudo-class |
| Design Attribute | Figma Design Token | C++ Views (Desktop) | WebUI (Web Frontend) |
|---|---|---|---|
| Base Foreground (Color) | currentColor / Derived from slot context | Inherited theme foreground color | color: var(--cr-icon-button-fill-color, currentColor); |
| Hover Background Circle | --desktop/sys/state-colors/state-hover-on-subtle | ||
(rgba(31,31,31,0.06)) | Handled via InkDropHost controller overlays | background-color: var(--cr-hover-background-color); | |
| Active/Pressed Ripple | --desktop/sys/state-colors/state-hover-on-prominent | ||
(rgba(31,31,31,0.12)) | Handled via dynamic ink drop color blending | Resolved via <cr-ripple> opacity / #ink target | |
| Disabled Icon Opacity | --desktop/sys/state-colors/state-disabled | ||
(rgba(31,31,31,0.38)) | Handled automatically by Views disabling shader | opacity: var(--cr-disabled-opacity); (Resolves to 0.38) | |
| Corner Radius | --desktop/corner-radius/fully-rounded | ||
(999px) | Circular clipping matches button radius | border-radius: 50%; (Circular mask) | |
| Standard Size Outer Dimension | 28px / 32px depending on size | Bounded by standard layout insets / preferred size | --cr-icon-button-size: 28px or 32px |
| Standard Size Inner Icon | 16px / 20px depending on size | Resolved by vector icon scale parameter | --cr-icon-button-icon-size: 16px; or 20px |
--desktop/corner-radius/fully-rounded (999px) on a square frame to enforce a circle.border-radius: 50% in its core stylesheet. While visually identical, the implementation uses raw percentage calculations instead of relying on the system-defined fully-rounded px variable.16dp and 20dp.32px and 28px are the primary styles, developers can scale the icon button arbitrarily to match settings panes or narrow sidebars by manually overriding the --cr-icon-button-size and --cr-icon-button-icon-size custom properties directly in the layout context.gfx::Insets struct during instantiation.transform: scaleX(-1)) in RTL locales. To prevent this, developers must explicitly pass the suppressRtlFlip boolean attribute.box-shadow: inset 0 0 0 2px var(--cr-focus-outline-color) which draws the outline inside the button bounds.48px to guarantee physical interactability on touchscreen layouts.<cr-icon-button> contains no visible text, it MUST have an explicit aria-label or aria-labelledby property.:focus-visible styling, and clicking is triggered by hitting Space or Enter.accessible_name string during button instantiation. Under the hood, Views registers this via GetViewAccessibility().SetName(accessible_name).SetFocusBehavior(FocusBehavior::ALWAYS) is retained to prevent the button from being skipped during keyboard tab cycles.views::View (Base layout unit)
└── views::Button (Focus, click handlers)
└── views::ImageButton (Renders state-dependent image models)
HTMLElement (Browser element base)
└── LitElement / CrLitElement (Reactive UI component)
└── CrIconButtonElement (with CrRippleMixin for active ripples)