Files
livewire-material/docs/reference/m3/components-actions-communication-containment.md
T
Andreas Reinhold / reiniandClaude Fable 5.1 651a513d1e Plan the Material 3 alignment, with the audits and Google's references
Every foundations, styles and components page of m3.material.io (238, from the
sitemap) extracted into docs/reference/m3, five audit reports with 142 findings in
docs/audits/m3-alignment, and the 2.0.0 plan in docs/plans/material-3-alignment.md.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
2026-09-14 03:53:40 +02:00

1464 lines
121 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Material Design 3 — Components Reference, Group A (Actions, Communication, Containment)
Ground-truth extraction from m3.material.io for auditing a Material 3 Expressive component library.
Scope: buttons (common), icon buttons, button groups, split button, segmented buttons, FAB, extended FAB,
FAB menu, badges, progress indicators, loading indicator, snackbar, tooltips, bottom sheets, cards,
carousel, dialogs, divider, lists, side sheets, menus.
Numeric specs not visible as text on m3.material.io (they are baked into token-table images) are sourced
from androidx Compose Material3 token files (`androidx-main` branch) or material-components-android docs,
as noted inline. Anything from my own knowledge is marked "(not on the site; from ...)".
Global tokens used repeatedly below (source: `StateTokens.kt`, `ElevationTokens.kt`, `ShapeTokens.kt`
androidx Compose Material3 tokens, androidx-main):
- State-layer opacities: Hover 0.08, Focus 0.10, Pressed 0.10, Dragged 0.16.
- Elevation levels (dp): Level0=0, Level1=1, Level2=3, Level3=6, Level4=8, Level5=12.
- Corner shape keys (dp): ExtraSmall=4, Small=8, Medium=12, Large=16, LargeIncreased=20, ExtraLarge=28,
ExtraLargeIncreased=32, ExtraExtraLarge=48, Full=fully rounded (stadium/circle).
## Buttons (common buttons)
**Status**: M3 available; M3 Expressive update **May 2025** (new sizes, toggle behavior, shape morph). Not deprecated.
### Anatomy
1. Label text
2. Container
3. Icon (optional, leading side)
### Variants and configurations (verbatim tables, source: specs page)
| Variant | M3 | M3 Expressive |
| --- | --- | --- |
| Default | Available | Available |
| Toggle (selection) | -- | Available |
| Category | Configuration | M3 | M3 Expressive |
| --- | --- | --- | --- |
| Size | Small (default) | Available | Available |
| | XS, M, L, XL | -- | Available |
| Shape | Round (default) | Available | Available |
| | Square | -- | Available |
| Color | Elevated, filled (default), tonal, outlined, text | Available | Available |
| Small button padding | 24dp | Available | Not recommended. Use 16dp |
| | 16dp | -- | Available |
Corner sizes (verbatim table, specs page):
| | XS | S | M | L | XL |
| --- | --- | --- | --- | --- |
| A. Round button | Full | Full | Full | Full | Full |
| B. Square button | 12dp | 12dp | 16dp | 28dp | 28dp |
| C. Pressed state | 8dp | 8dp | 12dp | 16dp | 16dp |
Color-by-state table (verbatim, specs page):
| | 1. Default | 2. Toggle unselected | 3. Toggle selected |
| --- | --- | --- | --- |
| Elevated container / icon & label | Surface container low / Primary | Surface container low / Primary | Primary / On primary |
| Filled container / icon & label | Primary / On primary | Surface container / On surface variant | Primary / On primary |
| Tonal container / icon & label | Secondary container / On secondary container | Secondary container / On secondary container | Secondary / On secondary |
| Outlined container / icon & label | Outline variant (outline) / On surface variant | Outline variant (outline) / On surface variant | Inverse surface / Inverse on surface |
| Text icon & label | Primary | -- | -- |
### Specs (numbers; source: androidx Compose Material3 tokens `ButtonXSmallTokens.kt`/`ButtonSmallTokens.kt`/`ButtonMediumTokens.kt`/`ButtonLargeTokens.kt`/`ButtonXLargeTokens.kt`, androidx-main)
| Size | Container height | Icon size | Icon↔label gap | Leading/trailing padding | Outlined outline width | Round corner | Square corner (resting) | Square corner (pressed) |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| XS | 32dp | 20dp | 8dp | 16dp | 1dp | Full | 12dp (Medium) | 8dp (Small) |
| S (default) | 40dp | 20dp | 8dp | 16dp (24dp legacy, not recommended) | 1dp | Full | 12dp (Medium) | 8dp (Small) |
| M | 56dp | 24dp | 8dp | 24dp | 1dp | Full | 16dp (Large) | 12dp (Medium) |
| L | 96dp | 32dp | 12dp | 48dp | 2dp | Full | 28dp (ExtraLarge) | 16dp (Large) |
| XL | 136dp | 40dp | 16dp | 64dp | 3dp | Full | 28dp (ExtraLarge) | 16dp (Large) |
Elevation by style and state (source: `FilledButtonTokens.kt`, `ElevatedButtonTokens.kt`, `FilledTonalButtonTokens.kt`, `TonalButtonTokens.kt` — androidx-main; dp values from `ElevationTokens.kt`):
- Elevated: rest = Level1 (1dp), hovered = Level2 (3dp), focused/pressed = Level1 (1dp), disabled = Level0 (0dp). Site text confirms: "elevated button style has an elevation of 1 by default and 0 when disabled."
- Filled / Tonal: rest = Level0 (0dp), hovered = Level1 (1dp), focused/pressed = Level0, disabled = Level0.
- Outlined / Text: no elevation (container invisible at rest for text; outlined has 1dp/2dp/3dp border per size above, no shadow).
- Disabled container opacity: Filled/Elevated/Text = 0.1; Tonal = 0.12 (source: token files). Disabled label/icon opacity = 0.38 (all styles).
Typography role: Label large (implied by `FilledTonalButtonTokens.LabelTextFont = LabelLarge`; not stated per-size on site — "(from androidx Compose Material3 tokens)").
Touch target: extra small and small buttons must have a 48x48dp minimum target size (specs page, "Target areas").
### Behaviour and guidelines (Google's wording)
- Two variants: **default** and **toggle**. Toggle buttons are for binary selections (e.g. Save/Favorite); on press they can change color, shape, and label.
- Toggle buttons use an outlined icon when unselected and a filled icon when selected (or increase weight if no filled version exists). By default, toggle buttons change from **round to square when selected**; if resting unselected shape is square, selected shape should be round.
- Shape morph on press: buttons morph to become more square when pressed; round and square buttons should have the same pressed shape (corner values in table above).
- Five color styles in order of emphasis: elevated > filled > tonal > outlined > text.
- **Filled**: highest visual impact after FAB; for important, final actions (Save, Join now, Confirm); use sparingly, ideally one per page; can use tertiary color.
- **Elevated**: same as tonal but with shadow; use only when the button needs separation from a visually prominent background; use sparingly.
- **Tonal**: for a lower-priority button that needs more emphasis than outlined (e.g. "Next" in onboarding); uses secondary color mapping.
- **Outlined**: medium-emphasis, pairs with filled buttons for secondary actions; stroke, no fill by default; place on simple backgrounds (not images/video) — visually similar to chips, use caution.
- **Text**: lowest priority, especially with multiple options; container invisible until interaction; never underline (use hyperlinked body text for links instead); common in cards, dialogs, snackbars.
- Do: keep width dynamic to fit label; label text sentence case, 1-3 words, never wrapped/truncated; icon leading side (left in LTR, right in RTL); icon and label stay grouped/centered as width changes; align dialog text buttons to the trailing edge.
- Don't: clutter UI with too many buttons (use overflow menus/icon buttons instead); set a fixed width narrower than the label; use two icons in one button; vertically stack icon+label; let label length change dramatically between toggle states; stretch buttons into long flat shapes on large windows.
- Buttons combine into button groups (primary/secondary emphasis via size/color/shape).
- Adaptive: on large screens, buttons can reposition (e.g. end-aligned below content in compact, start-aligned beside content in large windows); keep order consistent across breakpoints for screen readers/keyboard nav.
- Differences from M2: new color mappings + dynamic color compatibility, icon/label share one color, neutral text button no longer recommended; standard icon size now 20dp; fully-rounded corners + more height options; M2 height was 36dp with slight rounding vs M3 default (S) height 40dp fully rounded.
### Accessibility
- Role/use case: assistive tech must be able to use a button to perform an action, and navigate to/activate it.
- Color contrast: enabled buttons need **3:1** contrast with background; measured from the container for elevated/filled/tonal, from the label text for outlined/text.
- 200% text size: labels should stay concise enough to fit two lines at 200% zoom on Android; if truncated, provide an alternate way to reach full content in one tap.
- Rapid clicks (web): use a modified motion curve to avoid resonant animation effects on repeated taps.
- Keyboard: Tab = navigate to button; Space or Enter = activate.
- Labeling: accessibility label should match the visible label text (e.g. "Done", "Send", "Reply"); may add extra context.
- Touch target: XS/S buttons need 48x48dp minimum target (see Specs).
### Source URLs
- https://m3.material.io/components/buttons/overview (4525 bytes)
- https://m3.material.io/components/buttons/guidelines (24059 bytes)
- https://m3.material.io/components/buttons/specs (10787 bytes)
- https://m3.material.io/components/buttons/accessibility (3033 bytes)
- Token files: ButtonXSmallTokens.kt, ButtonSmallTokens.kt, ButtonMediumTokens.kt, ButtonLargeTokens.kt, ButtonXLargeTokens.kt, FilledButtonTokens.kt, ElevatedButtonTokens.kt, FilledTonalButtonTokens.kt, TonalButtonTokens.kt, OutlinedButtonTokens.kt, TextButtonTokens.kt, BaselineButtonTokens.kt, ElevationTokens.kt, ShapeTokens.kt, StateTokens.kt (androidx/androidx, androidx-main)
## Icon buttons
**Status**: M3 available; M3 Expressive update **May 2025** (new shapes/sizes/widths, shape morph, button-group interaction). Not deprecated. Known in M2 as "toggle buttons"; M3 splits into default and toggle variants.
### Anatomy
1. Icon
2. Container
### Variants and configurations (verbatim tables, source: specs page)
| Variant | M3 | M3 Expressive |
| --- | --- | --- |
| Default | Available | Available |
| Toggle (selection) | Available | Available |
| Category | Options | M3 | M3 Expressive |
| --- | --- | --- | --- |
| Size | Small (default) | Available | Available |
| | XS, M, L, XL | -- | Available |
| Shape | Round (default) | Available | Available |
| | Square | -- | Available |
| Color | Filled (default), tonal, outlined, standard | Available | Available |
| Width | Default | Available | Available |
| | Narrow, wide | -- | Available |
Corner radius (verbatim, specs page):
| | XS | S | M | L | XL |
| --- | --- | --- | --- | --- | --- |
| A. Round button | Full | Full | Full | Full | Full |
| B. Square button | 12dp | 12dp | 16dp | 28dp | 28dp |
| C. Pressed state | 8dp | 8dp | 12dp | 16dp | 16dp |
Color-by-state (verbatim, specs page):
| | 1. Default | 2. Toggle, unselected | 3. Toggle, selected |
| --- | --- | --- | --- |
| Filled container / icon | Primary / On primary | Surface container / On surface variant | Primary / On primary |
| Tonal container / icon | Secondary container / On secondary container | Secondary container / On secondary container | Secondary / On secondary |
| Outlined container / icon | Outline variant (outline) / On surface variant | Outline variant (outline) / On surface variant | Inverse surface / Inverse on surface |
| Standard icon | On surface variant | On surface variant | Primary |
Note: filled/tonal/outlined icon button tokens are called out on the specs page as **deprecated in favor of the new size-based token sets** (XSmall/Small/Medium/Large/XLarge IconButtonTokens).
### Specs (numbers)
Sizes (source: site guidelines text, confirmed against `XSmallIconButtonTokens.kt``XLargeIconButtonTokens.kt`, androidx-main):
| Size | Container size | Icon size | Round corner | Square corner (resting) | Square corner (pressed) | Outlined outline width |
| --- | --- | --- | --- | --- | --- | --- |
| XS | 32dp | 20dp | Full | 12dp (Medium) | 8dp (Small) | 1dp |
| S (default) | 40dp | 24dp | Full | 12dp (Medium) | 8dp (Small) | 1dp |
| M | 56dp | 24dp | Full | 16dp (Large) | 12dp (Medium) | 1dp |
| L | 96dp | 32dp | Full | 28dp (ExtraLarge) | 16dp (Large) | 2dp |
| XL | 136dp | 40dp | Full | 28dp (ExtraLarge) | 16dp (Large) | 3dp |
Width paddings — leading/trailing space per width, per size (source: token files above; "--" = not defined for that size, L uses "Uniform" instead of "Default"):
| Size | Narrow | Default | Wide |
| --- | --- | --- | --- |
| XS | 4dp | 6dp | 10dp |
| S | 4dp | 8dp | 14dp |
| M | 12dp | 16dp | 24dp |
| L | 16dp | 32dp (Uniform) | 48dp |
| XL | 32dp | 48dp | 72dp |
Selected-state shape swap is inverted for XS/S/M vs L/XL: at XS/S/M, `SelectedContainerShapeRound = Medium/Large` (i.e. selected round becomes the *square*'s corner value) and `SelectedContainerShapeSquare = Full`; check against source token files if auditing shape-morph-on-select logic.
State-layer opacities (specs page + `StateTokens.kt`): Disabled = 10% state layer (with reduced base opacity per token), Hovered = 8%, Focused = 10%, Pressed = 10% — same global values as Buttons.
Touch target: XS and S icon buttons must have a **48x48dp** (48x48 CSS px on web) minimum target size, even when nested or under a "density" option (accessibility page).
### Behaviour and guidelines (Google's wording)
- Two variants: **default** (opens menus/search, momentary actions) and **toggle** (binary on/off, e.g. favorite/bookmark).
- Four color styles, in order of emphasis: **filled** (highest, use sparingly for key actions like download/delete) > **tonal** (secondary action beside a high-emphasis one, e.g. "Raise hand" next to "End call") > **outlined** (medium emphasis, e.g. browsing card sets) > **standard** (lowest emphasis, or on colorful surfaces).
- Default icon buttons should use **filled** icons; toggle buttons use **outlined** icon unselected → **filled** icon selected. If no filled variant exists, bump weight to semibold (then bold) so selection is communicated by more than color alone — this requirement does **not** apply to non-toggle default buttons.
- Shape morph: buttons become more square when pressed (corner values in table); toggle buttons also morph round↔square between unselected/selected (whichever is the resting shape, the other is used when selected).
- On web, hovering an icon button shows a tooltip with the accessibility label (not the icon's literal name).
- Icon buttons placed in a standard button group interact with each other on press (shared with Button groups).
- Do: use same size for buttons of equal importance; use color/size to establish hierarchy for primary vs secondary actions; use toggle buttons only for things with a real selected state.
- Don't: use a toggle icon button for actions without a selected state (e.g. an overflow-menu button); overuse the filled style on one screen; apply density to icon buttons by default (it drops the target below 48x48).
### Accessibility
- Assistive tech must: understand the icon's meaning, navigate to/activate the button, and (where applicable) get a tooltip describing its purpose.
- Icon contrast ≥ **3:1** with background.
- Keyboard: Tab focuses a non-disabled icon button; Space or Enter activates it.
- Labeling: accessibility label states the action (e.g. "Add to favorites", "Bookmark", "Send message"), not the icon's shape.
- Layout/density: target size ≥48dp even inside dense/nested layouts; any density control itself must keep a 48x48 CSS px target.
- Hover (web): tooltip carries the accessibility label text, clear and concise.
### Source URLs
- https://m3.material.io/components/icon-buttons/overview (4167 bytes)
- https://m3.material.io/components/icon-buttons/guidelines (11967 bytes)
- https://m3.material.io/components/icon-buttons/specs (10990 bytes)
- https://m3.material.io/components/icon-buttons/accessibility (3907 bytes)
- Token files: XSmallIconButtonTokens.kt, SmallIconButtonTokens.kt, MediumIconButtonTokens.kt, LargeIconButtonTokens.kt, XLargeIconButtonTokens.kt, IconButtonTokens.kt, FilledIconButtonTokens.kt, FilledTonalIconButtonTokens.kt, OutlinedIconButtonTokens.kt (androidx/androidx, androidx-main)
## Button groups
**Status**: New component, **M3 Expressive only** (added May 2025). No M3-baseline "standard button group"; "connected button group" is the successor to the (now-deprecated) segmented button. Not deprecated itself.
### Anatomy
Button groups are invisible containers that add padding between buttons and modify button shape; they contain no buttons by default.
1. Container
### Variants and configurations (verbatim tables, source: specs page)
| Variant | M3 | M3 Expressive |
| --- | --- | --- |
| Standard button group | -- | Available |
| Connected button group | Available as segmented button (deprecated in the expressive update — use a nav rail instead) | Available |
| Category | Configuration | M3 | M3 Expressive |
| --- | --- | --- | --- |
| Size | XS, S, M, L, XL | -- | Available |
| Default shape | Round, square | -- | Available |
| Selection | Single-select, multi-select, selection-required | Available as segmented button (deprecated) | Available |
Common layouts (anatomy page): label buttons; label + icon buttons; extra-small icon buttons; large icon buttons. Color: button groups have no color of their own — they inherit filled/tonal/outlined/elevated styles from the buttons inside; avoid standard icon buttons or text buttons in a group (no container to show grouping).
### Specs (numbers; source: specs page unless noted)
Standard button group inner padding (between buttons), by size:
| Size | XS | S | M | L | XL |
| --- | --- | --- | --- | --- | --- |
| Inner padding | 18dp | 12dp | 8dp | 8dp | 8dp |
(Cross-check, source `ButtonGroupSmallTokens.kt`: Small `BetweenSpace` = 12dp, `ContainerHeight` = 40dp — matches site.)
Connected button group: inner padding is **2dp at every size** (round and square). Outer shape is fully round for round groups; inner (between-button) corner sizes and outer corner sizes for square groups:
| Size | XS | S | M | L | XL |
| --- | --- | --- | --- | --- | --- |
| Corner size | 4dp | 8dp | 8dp | 16dp | 20dp |
(Cross-check, source `ConnectedButtonGroupSmallTokens.kt`: `BetweenSpace` = 2dp, `ContainerHeight` = 40dp, `ContainerShape` = Full, `InnerCornerCornerSize` = CornerValueSmall (8dp) at rest, `PressedInnerCornerCornerSize` = CornerValueExtraSmall (4dp), `SelectedInnerCornerCornerSizePercent` = 50%.)
Minimum widths: XS and S connected button groups have a 48dp target area and a **48dp minimum width**.
Density: button groups adapt to the density of the buttons inside (0, -1, -2, -3 density steps shown on site); no button-group-specific density tokens beyond the buttons'.
### Behaviour and guidelines (Google's wording)
- **Standard button groups**: add interaction between adjacent buttons. When a button is selected/activated, it changes shape and its own + adjacent buttons' width briefly change (padding scales with size to keep 48dp accessible targets). Toggle buttons inside a standard group swap shape square/round on selection, colored per the common-button color spec.
- **Connected button groups**: do NOT affect adjacent buttons; selecting/activating only changes the shape of that one button. Should replace the (deprecated) baseline segmented button. Use for single-select, multi-select, or selection-required patterns with toggle buttons; avoid a connected group when none of its buttons can be toggled.
- By default all buttons in a **standard** group should share the same size (XSXL) and shape (round/square); only mix sizes for "hero moments," and reserve shape differences for key/selected interactions.
- **Connected** groups should span the width of their page/surface (buttons grow to fill it); consider a max-width on large windows. Avoid mixing color styles within a connected group — it muddies selection/emphasis (explicit Don't).
- Adaptive/resizing: groups move through layouts as a single line and never wrap to a second line; multiple groups can stack vertically but don't interact with each other. Buttons/groups can be **fixed** (manually set width/size/padding per breakpoint) or **flexible** (auto-grow until all flexible buttons hit max width); don't stretch icon buttons past their "wide" setting.
### Accessibility
- Assistive tech must be able to navigate to and interact with each button in the group, and identify when a button is selected.
- Each button needs a minimum **48x48dp** target; XS/S groups get extra inner padding specifically to preserve this — don't reduce it.
- Initial focus: the group container itself is **not focusable**; initial focus lands on the first button, then moves button-to-button.
- Keyboard: **Tab** navigates to the next button; **Space** or **Enter** activates/selects the focused button.
- Labeling: the button-group container itself needs no label; label each button per the Buttons/Icon buttons accessibility guidance.
### Source URLs
- https://m3.material.io/components/button-groups/overview (7045 bytes)
- https://m3.material.io/components/button-groups/guidelines (9749 bytes, refetched with cache-bypass header after a stale/empty cached render)
- https://m3.material.io/components/button-groups/specs (9507 bytes)
- https://m3.material.io/components/button-groups/accessibility (2891 bytes — short but complete)
- Token files: ButtonGroupSmallTokens.kt, ConnectedButtonGroupSmallTokens.kt, ShapeTokens.kt (androidx/androidx, androidx-main)
## Split button
**Status**: New component, **M3 Expressive only** (added May 2025, "New component added to catalog"). No M3-baseline availability. Not deprecated. Note: the base page `components/split-button` (no `/overview` suffix) IS its overview page; sub-pages `specs`, `guidelines`, `accessibility` exist under `/components/split-button/*`.
### Anatomy
1. Leading button
2. Icon
3. Label text
4. Trailing button (menu button — always carries the expand/collapse icon, rotates 180° inward when opened/closed, never customize this icon)
### Variants and configurations (verbatim tables, source: specs page)
| Variant | M3 | M3 Expressive |
| --- | --- | --- |
| Split button | -- | Available |
| Category | Configuration | M3 | M3 Expressive |
| --- | --- | --- | --- |
| Size | XS, S, M, L, XL | -- | Available |
| Color | Elevated, filled, tonal, outlined | -- | Available |
Same five size steps as buttons/icon buttons: extra small, small (default), medium, large, extra large. Leading button can show icon, label, or both; trailing button is always a menu icon button.
### Specs (numbers)
Container height per size — same scale as common buttons (source: `SplitButton{Size}Tokens.kt`, androidx-main, cross-checked against `Button{Size}Tokens.kt`):
| Size | Container height | Between-button space | Trailing icon size | Leading btn L/T padding | Trailing btn L/T padding | Inner corner (rest) | Inner corner (hover/press) |
| --- | --- | --- | --- | --- | --- | --- | --- |
| XS | 32dp | 2dp | 22dp | 12dp / 10dp | 13dp / 13dp | 4dp (ExtraSmall) | 8dp (Small) |
| S | 40dp | 2dp | 22dp | 16dp / 12dp | 13dp / 13dp | 4dp (ExtraSmall) | 12dp (Medium) |
| M | 56dp | 2dp | 26dp | 24dp / 24dp | 15dp / 15dp | 4dp (ExtraSmall) | 12dp (Medium) |
| L | 96dp | 2dp | 38dp | 48dp / 48dp | 29dp / 29dp | 8dp (Small) | 20dp (LargeIncreased) |
| XL | 136dp | 2dp | 50dp | 64dp / 64dp | 43dp / 43dp | 12dp (Medium) | 20dp (LargeIncreased) |
(Site's own "inner corner radius" figure, specs page: XS 4dp, S 4dp, M 4dp, L 8dp, XL 12dp at rest — matches token file `InnerCornerCornerSize` above; between-button space is stated on-site as "always 2dp".)
Menu icon offset from center when unselected (site, specs page): XS/S = -1dp, M = -2dp, L = -3dp, XL = -6dp.
Outer container shape: fully rounded (`CornerFull`) at every size. Trailing inner-selected corner and outer corner both use a 50% corner-size percent (i.e. scale with half the button height) per token file.
Color: split buttons reuse the same color roles and state layers as common buttons (elevated/filled/tonal/outlined) — see Buttons color table. Unlike toggle buttons, **selecting the split button's menu does not change its color** — only a state layer (hover/focus/press) is applied, plus the trailing icon rotates and its inner corners morph.
Touch target: every button in the split button needs a **48x48dp** minimum target; XS/S split buttons are shorter than 48dp so the surrounding target area must still be ≥48dp tall.
### Behaviour and guidelines (Google's wording)
- Use to show a main action plus a menu of related actions; reduces visual complexity by hiding extra options. Works alone or alongside other buttons/icon buttons/button groups, and can be sized independently from neighboring controls (e.g. a large primary split button next to smaller controls).
- Scale up the split button on large breakpoints, or in small windows to create emphasis for "hero moments."
- The trailing (menu) button uses the **standard motion scheme**, not expressive, when rotating; it rotates 180° inward on open/close and applies shape morph when selected.
- Menu placement: align the opened menu with the trailing button when possible; if there isn't room, align to one side of the leading/trailing button; the menu should sit **4dp** from the split button; always try to keep it anchored to one of the button's edges.
- Do: open a menu from a split button; keep the leading label brief (1-2 words) with a clearly matching icon.
- Don't: modify the trailing icon or use very long labels; modify the opened menu in unusual/irregular ways.
- RTL: the whole component (leading/trailing order) mirrors in right-to-left languages.
### Accessibility
- Assistive tech must be able to: navigate to and interact with each button, navigate to whatever the trailing button opens, and understand the current selection state.
- Touch target ≥48x48dp per button (see Specs).
- Initial focus lands on the **leading button**, then moves to the **trailing button** (subject to OS settings).
- Keyboard: Tab navigates between buttons; Space or Enter activates the focused button.
- Labeling: leading button's accessibility label matches its visible label, same rules as common Buttons. Trailing (menu) button needs an expanded/collapsed state or equivalent label communicating more options are available (e.g. main button "Watch later" → trailing button labeled like "More watch options"). The opened menu should follow the Menus accessibility guidance.
### Source URLs
- https://m3.material.io/components/split-button (1565 bytes — the component's overview page; short but complete, genuinely a small page)
- https://m3.material.io/components/split-button/specs (6142 bytes)
- https://m3.material.io/components/split-button/guidelines (7964 bytes)
- https://m3.material.io/components/split-button/accessibility (7866 bytes)
- Token files: SplitButtonXSmallTokens.kt, SplitButtonSmallTokens.kt, SplitButtonMediumTokens.kt, SplitButtonLargeTokens.kt, SplitButtonXLargeTokens.kt, ShapeTokens.kt (androidx/androidx, androidx-main)
## Segmented buttons
**Status**: M3 available. **Deprecated in the M3 Expressive update** — the site's own Button groups pages state segmented buttons "are deprecated in the expressive update. Use a nav rail instead," and that connected button groups should replace the baseline segmented button. The segmented-buttons overview page's own "M3 Expressive update" section is empty (no expressive changes were added to this component). Previously called "toggle buttons" in M2.
### Anatomy
1. Segment
2. Container
3. Icon (optional; replaced by a checkmark icon when a segment with both icon+label is selected)
4. Label text (optional)
5. Selected icon (checkmark)
### Variants and configurations
Two variants: **single-select** (radio-button-like, exactly one segment selected) and **multi-select** (checkbox-like, 0 to all segments selected). 2-5 segments per button (site: "Don't use more than five segments... consider chips instead"); use for simple choices between two and five items, use chips for more/complex choices.
### Specs (verbatim table, source: specs page)
| Attribute | Value |
| --- | --- |
| Container width | Dynamic based on labels |
| Segment width | Container width / total segments |
| Height | 40dp |
| Outline width | 1dp |
| Label alignment | Center |
| Left/right padding | Min 12dp |
| Padding between elements | 8dp |
| Target size | 48dp |
Cross-check, source `OutlinedSegmentedButtonTokens.kt` (androidx-main): `ContainerHeight` = 40dp, `OutlineWidth` = 1dp, `Shape` = CornerFull, `LabelTextFont` = LabelLarge, `DisabledOutlineOpacity` = 0.12, `DisabledIconOpacity`/`DisabledLabelTextOpacity` = 0.38.
Color roles used (site, specs page): On surface, Outline, Secondary container, On secondary container — i.e. unselected = outlined (Outline border, On surface content), selected = Secondary container fill / On secondary container content.
Density: density only affects height; each density step down removes **4dp** from the 40dp height.
Shape: fully rounded corners by default (like common buttons); M2 used a small corner radius.
### Behaviour and guidelines (Google's wording)
- Segmented buttons help people select options, switch views, or sort elements.
- **Single-select**: choose exactly one from up to five options (e.g. beverage size).
- **Multi-select**: select/sort from 2-5 options; not required — anywhere from none to all can be selected (e.g. price-range filter).
- Icons: may be used alone or with text; icon-only segments must clearly communicate their meaning on their own. Don't mix icon-only segments with text-label segments in the same button — pick one label type and use it throughout.
- Labels: short and succinct; if too long to fit, use an icon alone instead. Don't let segments wrap to a new line.
- Behavior: when a segment uses both icon and label, the icon is replaced by a **checkmark** on selection.
- Placement: keep adequate margin from the viewport/frame edge — the container shouldn't touch the edge; on large screens, cap the internal padding per segment (don't let the button span full width, which leaves too much empty padding inside segments). Can be placed inside bottom sheets or full-screen dialogs.
### Accessibility
- Assistive tech must be able to navigate to/activate segments and understand what each selection does.
- Color contrast: outline needs ≥**3:1** against the surface (clusters of similar components need the outline to read clearly); selection must be shown by **both** a checkmark and a color change — never color alone.
- Initial focus: lands on the first segment (leftmost in LTR, rightmost in RTL), regardless of selection state.
- Keyboard: **Tab** moves focus to the next enabled segment (both variants). **Space/Enter**: single-select = select the focused segment (radio-like — can't be unselected by re-pressing, matches radiogroup semantics); multi-select = toggle the focused segment on/off (checkbox-like).
- Roles: single-select segmented button = **Radiogroup**; multi-select = **Checkbox** (per-segment).
- Labeling: accessibility label = visible label text (e.g. "Relevance", "Distance"); if icon-only, label describes the action/meaning (e.g. "Inexpensive" for a "$" icon).
### Source URLs
- https://m3.material.io/components/segmented-buttons/overview (3627 bytes)
- https://m3.material.io/components/segmented-buttons/guidelines (10516 bytes)
- https://m3.material.io/components/segmented-buttons/specs (4360 bytes)
- https://m3.material.io/components/segmented-buttons/accessibility (5770 bytes)
- Token file: OutlinedSegmentedButtonTokens.kt (androidx/androidx, androidx-main)
## FAB (floating action button)
**Status**: M3 available; M3 Expressive update **May 2025** (new **medium** size, new tone color styles, renamed tonal styles). Not deprecated, but **small FAB is "no longer recommended"** and **surface-color FABs are "no longer recommended."**
### Anatomy
1. Container (square-ish, rounded corners; must not be covered by other elements e.g. badges)
2. Icon (should be filled, not outlined; a FAB shouldn't carry notifications/badges for actions found elsewhere)
### Variants and configurations (verbatim tables, source: specs page)
| Variant | M3 | M3 Expressive |
| --- | --- | --- |
| FAB | Available | Available |
| Medium FAB | -- | Available |
| Large FAB | Available | Available |
| Small FAB | Available | Not recommended. Use a larger size. |
| Category | Configuration | M3 | M3 Expressive |
| --- | --- | --- | --- |
| Color | Primary container, secondary container, tertiary container | Available as primary, secondary, tertiary | Available |
| | Primary, secondary, tertiary | -- | Available |
Expressive rename note (site): the old **primary/secondary/tertiary** tonal styles were renamed **primary container/secondary container/tertiary container** to match their actual token names (values unchanged); new **primary/secondary/tertiary** (non-container) styles were added separately. Surface-color FAB styles still exist but are "no longer recommended."
### Specs (numbers; source: `FabBaselineTokens.kt`, `FabSmallTokens.kt`, `FabMediumTokens.kt`, `FabLargeTokens.kt`, androidx-main — the specs page shows only image diagrams for these, no text values)
| Size | Container height × width | Icon size | Corner shape |
| --- | --- | --- | --- |
| Small (not recommended) | 40×40dp | 24dp | Medium (12dp) |
| FAB (default/regular) | 56×56dp | 24dp | Large (16dp) |
| Medium | 80×80dp | 28dp | LargeIncreased (20dp; token has a TODO placeholder pending that shape key) |
| Large | 96×96dp | 32dp | ExtraLarge (28dp) |
Elevation and state layers (source `FabPrimaryContainerTokens.kt`/`FabSecondaryContainerTokens.kt`, androidx-main; dp via `ElevationTokens.kt`; state-layer % confirmed on specs page):
- Rest = Level3 (6dp); Hovered = Level4 (8dp) with 8% state layer; Focused = Level3 (6dp) with 10% state layer; Pressed = Level3 (6dp) with 10% state layer.
- Rule: when using a non-default color mapping, the state-layer color must match the icon color (e.g. primary style → state layer = `md.sys.color.primary`).
- Icon contrast requirement: ≥3:1 against the container (accessibility page).
### Behaviour and guidelines (Google's wording)
- Use a FAB for the **most important/common action** on a screen; it floats in front of all other content and persists while content scrolls.
- Three sizes, chosen by breakpoint/hierarchy: **FAB** (smallest, best in compact windows alongside other on-screen actions); **medium FAB** ("most recommended," works in compact and medium windows, for important actions without taking much space); **large FAB** (any window size where the primary action needs to be prominent, best in expanded+ breakpoints).
- Don't display **multiple FABs on one screen**; individual components like cards shouldn't each have their own FAB.
- A FAB can morph into an **extended FAB** on larger screens, or into a **FAB menu** when it has many related actions.
- Use for constructive actions: Create, Favorite, Share, Start a process. Don't use for minor/destructive actions: archive/trash, alerts/errors, limited tasks (e.g. cut text), or controls better suited to a toolbar (e.g. volume, font color).
- Container needs sufficient contrast with its background; icon should be filled (not outlined) and unambiguous; on web, hovering shows a tooltip with a text label.
- Adaptive placement: compact/medium breakpoints → lower right (bottom trailing) corner; expanded breakpoints → consider upper-left, e.g. embedded in a navigation rail. Use medium FAB on mobile, large FAB on tablets/large screens.
- Motion/behavior: appears by expanding outward from a central point (icon can animate too); FABs move independently of other UI (not attached to the content surface). On screen-layout transitions the FAB should disappear and reappear (only if relevant to the new screen, ideally in the same position). Can container-transform/expand into another surface or into a FAB menu. Stays fixed on scroll; an **extended FAB can collapse to a FAB on scroll and re-expand at the bottom of the view**. When switching tabs, the FAB should briefly disappear and reappear (signals it isn't tied to a specific tab) — don't animate it together with body content.
- Differences from M2: M2 FABs were circular with an always-on drop shadow; M3 FABs are boxier (rounded-square), support dynamic color, and add the large-FAB variant.
### Accessibility
- Assistive tech must be able to: navigate to/activate the FAB, perform its action, and expand/minimize an extended FAB.
- **Never disable a FAB** — if its action is unavailable, remove the FAB entirely instead.
- Icon-to-container contrast ≥ **3:1**.
- Focus order: the FAB should be prioritized in the page's focus order — e.g. mobile order can go app bar → navigation bar → skip other content → FAB. Consider a tooltip on focus (supported on web).
- Layout: on expanded breakpoints, consider upper-left placement for easier reach via screen reader; on compact/medium, lower-right. On web, a FAB may partially cover another actionable element but must never fully obscure that element's focus indicator.
- Keyboard: Tab focuses the FAB; Space or Enter performs its default action.
- Labeling: accessibility label names the action (e.g. "Compose a new message"), not the icon shape.
### Source URLs
- https://m3.material.io/components/floating-action-button/overview (3173 bytes)
- https://m3.material.io/components/floating-action-button/guidelines (11707 bytes)
- https://m3.material.io/components/floating-action-button/specs (6803 bytes)
- https://m3.material.io/components/floating-action-button/accessibility (5818 bytes)
- Token files: FabBaselineTokens.kt, FabSmallTokens.kt, FabMediumTokens.kt, FabLargeTokens.kt, FabPrimaryContainerTokens.kt, FabSecondaryContainerTokens.kt, ElevationTokens.kt (androidx/androidx, androidx-main)
## Extended FAB
**Status**: M3 available (as a single "baseline" size); M3 Expressive update **May 2025** replaces it with three sizes (small/medium/large). **Baseline extended FAB and surface-color extended FABs are "no longer recommended."**
### Anatomy
1. Container (rounded rectangle, hugs its contents, grows/shrinks with label length)
2. Label text (required — unlike the plain FAB, an extended FAB cannot have an icon without a label)
3. Icon (optional — unlike the plain FAB, the extended FAB does NOT require an icon)
### Variants and configurations (verbatim table, source: specs page)
| Variant | M3 | M3 Expressive |
| --- | --- | --- |
| Small extended FAB | -- | Available |
| Medium extended FAB | -- | Available |
| Large extended FAB | -- | Available |
| Extended FAB (baseline) | Available | Not recommended. Use **small extended FAB.** |
Baseline → small migration note (site): type style changed from **label large** to **title medium**, and inner padding was reduced.
### Specs (numbers)
Baseline extended FAB (verbatim table, specs page):
| Attribute | Value |
| --- | --- |
| Container height | 56dp |
| Container width | Dynamic, 80dp min |
| Container shape | 16dp corner radius |
| Icon size | 24dp |
| Padding | 16dp |
Site text (overview page) gives the three expressive sizes' heights directly: **Small 56dp, Medium 80dp, Large 96dp** — matching the FAB's own size scale. Padding/icon-size detail for these three (source: `ExtendedFabSmallTokens.kt`/`ExtendedFabMediumTokens.kt`/`ExtendedFabLargeTokens.kt`, androidx-main — not shown as text on the specs page, only diagrams):
| Size | Container height | Corner shape | Icon size | Icon↔label gap | Leading/trailing padding |
| --- | --- | --- | --- | --- | --- |
| Small | 56dp | Large (16dp) | 24dp | 8dp | 16dp |
| Medium | 80dp | LargeIncreased (20dp; token has TODO pending shape-key availability) | 28dp | 16dp | 26dp |
| Large | 96dp | ExtraLarge (28dp) | 32dp | 20dp | 28dp |
Margins: extended FABs should have **16dp** margins from the screen edge (specs page, both baseline and updated variants).
Elevation/state (source `ExtendedFabPrimaryTokens.kt`, androidx-main): rest = Level3 (6dp); hovered = Level4 (8dp); focused/pressed = Level3 (6dp). A "lowered" elevation variant also exists (rest/focus/pressed = Level1 (1dp), hover = Level2 (3dp)) for contexts needing reduced prominence. State-layer color must match icon color for non-default color mappings (same rule as FAB).
Color styles: same six as FAB — primary container/on primary container (default), secondary container, tertiary container, primary, secondary, tertiary — plus a not-recommended surface-container style.
### Behaviour and guidelines (Google's wording)
- Use on screens with **long, scrolling views** that need persistent access to one action (e.g. checkout); use when label text helps clarify the action or adds emphasis, especially where an icon alone would be ambiguous (e.g. "Find flights" + airplane icon) — but the icon/label relationship must still be clear.
- Only **one extended FAB per screen** — multiple compete for attention; for more high-emphasis actions use ordinary buttons elsewhere. Don't use an extended FAB as one option within a set of actions — use a filled button instead for that.
- Choose size by breakpoint/emphasis: **large** extended FAB can suit compact windows with one prominent action; **medium or large** for larger breakpoints.
- Label: 1-2 words max, must clearly describe the action; never wrap or truncate (remember localization can lengthen labels/width).
- Placement: place above the rest of the UI, off elements like app bars. Don't place it on top of (docked/floating) toolbars — breaks elevation/surface consistency; don't place in the upper half of a mobile screen (disrupts reading order); don't place on cards or inside other containers. Floating toolbars can pair with a plain FAB but not with an extended FAB.
- Responsive: the FAB and extended FAB can transform into each other depending on space — a collapsed nav rail shows a FAB, an expanded rail can grow it into an extended FAB. RTL languages mirror icon/label order.
- Breakpoints: compact/medium → bottom of screen, center- or trailing-edge-aligned; expanded+ → bottom-right corner (both LTR/RTL) or inside the navigation rail.
- Motion: appears via an enter/exit expand transition; can container-transform into another surface; can **collapse to a FAB on scroll-down and re-expand to extended on scroll-up** — when switching between FAB↔extended FAB, shape changes, the icon moves left, and the text label fades in/out.
### Accessibility
- Assistive tech must be able to navigate to and activate the extended FAB.
- Placement for reachability: large web screens → upper-left (e.g. expanded nav rail); smaller windows → lower-right corner; never place over another actionable element.
- Focus order: prioritize the extended FAB in the page's focus order (e.g. app bar → nav bar → skip content → extended FAB). Treat the icon+label as **one single focusable element**.
- **No tooltip needed** — the visible label already serves that role (explicit Don't: adding a redundant tooltip).
- Keyboard: Tab moves focus to it; Space or Enter activates it.
- Labeling: keep icon and label semantically consistent (e.g. "Compose" icon + "Compose" label = one clear purpose). The accessibility label **must start with the same first word as the visible label** (e.g. visible "Create" → accessibility label "Create a new invite").
### Source URLs
- https://m3.material.io/components/extended-fab/overview (3531 bytes)
- https://m3.material.io/components/extended-fab/guidelines (14651 bytes)
- https://m3.material.io/components/extended-fab/specs (8565 bytes)
- https://m3.material.io/components/extended-fab/accessibility (4783 bytes)
- Token files: ExtendedFabSmallTokens.kt, ExtendedFabMediumTokens.kt, ExtendedFabLargeTokens.kt, ExtendedFabPrimaryTokens.kt, ElevationTokens.kt (androidx/androidx, androidx-main)
## FAB menu
**Status**: New component, **M3 Expressive only** (added May 2025). No M3-baseline availability. Not deprecated. Explicitly meant to **replace the speed dial pattern and stacked small FABs** from M2/earlier.
### Anatomy
1. Close button (replaces the FAB in place; always 56dp)
2. List item / menu item (icon + label; 2-6 items)
### Variants and configurations (verbatim tables, source: specs page)
| Variant | M3 | M3 Expressive |
| --- | --- | --- |
| FAB menu | -- | Available |
| Category | Configuration | M3 | M3 Expressive |
| --- | --- | --- | --- |
| Color | Primary set, secondary set, tertiary set | -- | Available |
One size fits all FAB sizes; **not used with extended FABs** (opens only from a plain FAB). Color sets: primary/secondary/tertiary — pick the set matching the triggering FAB's color style (primary or primary-container FAB → primary FAB-menu set, etc.).
### Specs (numbers; source: specs page text + `FabMenuBaselineTokens.kt`, androidx-main)
| Element | Value |
| --- | --- |
| Close button height/width | 56dp (always) |
| Close button shape | Full (fully rounded) |
| Close button icon size | 20dp |
| Close-button-to-item spacing | 8dp |
| Menu item height | 56dp (same scale as the Medium button/56dp — site says "share the same measurements as the medium button specs"; cross-check: `ButtonMediumTokens.ContainerHeight` = 56dp too, consistent) |
| Menu item shape | Full (fully rounded) |
| Menu item icon size | 24dp |
| Menu item icon↔label gap | 8dp |
| Menu item leading/trailing padding | 24dp |
| Item-to-item spacing | 4dp |
| Elevation (close button & items) | Level3 (6dp) |
| FAB↔menu gap (web) | 4dp recommended |
| Menu/FAB margin from screen edge | 16dp (compact/medium windows), **24dp** (large/extra-large windows) |
| Extra bottom margin when opened from medium FAB | 40dp from bottom of screen |
| Extra bottom margin when opened from large FAB | 56dp from bottom of screen |
Color roles used (specs page): On/Primary container, On/Primary, On/Secondary container, On/Secondary, On/Tertiary container, On/Tertiary (12 roles total, 4 per color set).
Touch target: all FAB menu elements meet the **48dp** minimum target size by default.
### Behaviour and guidelines (Google's wording)
- A FAB menu opens **only from a FAB** (never from an extended FAB or any other component) and always appears in the same place the FAB occupied — the FAB transforms into the close button.
- Contains **2-6 closely related items** under one action (e.g. "Share"); don't group unrelated actions, and don't use a FAB menu for just one item (use a plain FAB instead).
- Don't pair a FAB menu with a floating toolbar or navigation rail next to the same FAB (cognitive overload/clutter) — a plain FAB can be placed next to those, but not a FAB menu.
- Alignment: aligned to the trailing edge of the window; in RTL, aligned to the left edge with elements mirrored.
- Menu items must always show a label — icons are optional to remove only "if necessary" but should stay since they differentiate items; never remove the label. Items hug their content (no fixed/expanded widths, no truncation); all elements stay rounded — don't square them off.
- Color: choose the color set (primary/secondary/tertiary) that matches the FAB's own color style.
- Adaptive: stays anchored to the same corner/edge across window sizes; margins grow from 16dp to 24dp in large/XL windows; use a FAB size appropriate to the breakpoint. On web, the FAB menu is implemented as a Menu component for desktop-app consistency.
- Motion: FAB transforms into the close button; items animate in/out via enter-exit transition, originating from one of the FAB's trailing corners (preferably the top-aligned corner). Items can container-transform into another surface. On short viewports (e.g. landscape phone), items can scroll — they must scroll **behind** the close button, which stays fixed/unobstructed. On web, avoid positioning the menu so it fully obscures another element's focus indicator (partial cover with a visible indicator is fine).
### Accessibility
- Assistive tech must be able to navigate/interact with the menu and get correct focus while doing so.
- Touch target ≥48dp for every FAB menu element (met by default).
- Initial focus: when the FAB is activated, focus **stays on the close button** (which has replaced the FAB); Tab then moves focus **top-to-bottom** through the menu items.
- Keyboard: Tab moves to the next interactive element; Space or Enter activates the focused button/item.
- Labeling (Android): close button = Label "Toggle menu", Role Button, State Expanded/Collapsed. Menu items = label matches the visible item text (e.g. "Reply all"), Role Button.
- Labeling (Web): the FAB menu is a FAB + Menu combo — follow FAB accessibility guidance for the trigger and Menu accessibility guidance for the popup; the FAB's own accessibility label should describe what menu it opens.
### Source URLs
- https://m3.material.io/components/fab-menu/overview (7239 bytes)
- https://m3.material.io/components/fab-menu/guidelines (11593 bytes)
- https://m3.material.io/components/fab-menu/specs (7083 bytes)
- https://m3.material.io/components/fab-menu/accessibility (4470 bytes)
- Token file: FabMenuBaselineTokens.kt, ButtonMediumTokens.kt, ElevationTokens.kt (androidx/androidx, androidx-main)
## Badges
**Status**: M3 available. The overview page has **no "M3 Expressive update" section at all** — badges received no expressive-era changes. Not deprecated.
### Anatomy
1. Small badge (plain circle, no content)
2. Large badge container
3. Large badge label
4. Large badge maximum-character-count container (variant of 3, widened)
5. Large badge maximum-character-count label
### Variants and configurations
Two variants: **small badge** (plain circle, indicates an unread notification, no content) and **large badge** (contains label text — a count or short status, up to 4 characters including a trailing "+"). No verbatim variant/configuration table is published for badges (the specs page uses an interactive token browser instead of a static table); the two variants above are stated directly in prose on the overview/guidelines pages.
### Specs (verbatim table, source: specs page)
| Attribute | Value |
| --- | --- |
| Small badge shape | 3dp corner radius |
| Small badge size (H×W) | 6dp |
| Large badge shape | 8dp corner radius |
| Large badge one-digit size (H×W) | 16dp |
| Large badge max character count size (H×W) | 16×34dp |
| Small badge: distance from top-trailing icon corner to bottom-leading badge corner (H×W) | 6×6dp |
| Large badge: distance from top-trailing icon corner to bottom-leading badge corner (H×W) | 14×12dp |
| Large badge padding between badge and text container | 4dp |
Cross-check, source `BadgeTokens.kt` (androidx-main): `Size` = 6dp, `Shape` = CornerFull (a 6dp circle ⇒ 3dp radius, matches); `LargeSize` = 16dp, `LargeShape` = CornerFull (a 16dp circle ⇒ 8dp radius, matches); `LargeLabelTextFont` = LabelSmall.
Color (specs page): default color role is **Error** container / **On error** text — same role used in both navigation bar and navigation rail contexts. Guidelines/accessibility explicitly say to keep the default color mapping; if a custom color role is used, it must still hit **3:1** contrast.
Badge is anchored inside the icon's bounding box at the icon's **upper trailing edge**; a large badge's width grows with content but its anchor point doesn't move.
### Behaviour and guidelines (Google's wording)
- Used to show a notification, item count, or other status tied to a navigation destination; placed at the ending (trailing) edge of icons, typically nested inside other components (navigation bar, navigation rail, app bars, tabs).
- Small badge = simple circle for an unread notification (no text). Large badge = shows a count/status via label text, max **4 characters including a "+"** (e.g. "999+"); truncate rather than let text overflow or collide with neighboring elements.
- In navigation bars, **hide the badge once its destination has been selected**.
- Do: change badge position for RTL languages (mirror to the icon's other side). Don't: place a badge at an arbitrary/changing position or directly over the icon — position is fixed.
- Do: use the default badge color to avoid contrast/collision issues. Don't: use custom color roles unless they still clear 3:1 contrast.
- Placement: use a **large** badge for count info where visual collisions aren't a concern (e.g. navigation rail); use a **small** badge in tightly constrained spaces (e.g. app bars) so it doesn't run into the screen edge. When an icon+badge is followed by text/another element, put a large badge at the **trailing edge** rather than risk overlapping that element (or fall back to a small badge).
### Accessibility
- Assistive tech must be able to understand the dynamic info a badge conveys (counts/labels) and reach/select the corresponding navigation destination to address it.
- Contrast: badge (container + label) must be ≥**3:1**, same rule whether default or custom color.
- Labeling: badge is announced **after** its navigation destination's own label; a numeric badge has its number read aloud; a non-counting (small) badge announces simply **"New notification."**
- Behavior tie-in: hiding the badge after the destination is selected also removes its announcement once read/addressed.
### Source URLs
- https://m3.material.io/components/badges/overview (6336 bytes)
- https://m3.material.io/components/badges/guidelines (9108 bytes)
- https://m3.material.io/components/badges/specs (10128 bytes)
- https://m3.material.io/components/badges/accessibility (8004 bytes)
- Token file: BadgeTokens.kt (androidx/androidx, androidx-main)
## Progress indicators
**Status**: M3 available; M3 Expressive update **Aug 2024** (configurable track thickness, wavy shape). Earlier update Dec 2023 (NTC — non-text contrast: added stop indicator, higher track/indicator contrast, new motion, rounded corners). Not deprecated. Note: separate circular/linear baseline token sets are called out as "no longer recommended" (superseded by a unified token approach).
### Anatomy
1. Active indicator (shows progress made so far)
2. Track
3. Stop indicator (linear + determinate only)
### Variants and configurations (verbatim tables, source: specs page)
| Variant | M3 | M3 Expressive |
| --- | --- | --- |
| Linear progress indicator | Available | Available |
| Circular progress indicator | Available | Available |
| Category | Configuration | M3 | M3 Expressive |
| --- | --- | --- | --- |
| Behavior | Determinate (default), Indeterminate | Available | Available |
| Track thickness | Fixed (4dp) | Available | Available |
| | Configurable | -- | Available |
| Shape | Flat (default) | Available | Available |
| | Wavy | -- | Available |
### Specs (numbers; source `LinearProgressIndicatorTokens.kt`, `CircularProgressIndicatorTokens.kt`, `ProgressIndicatorTokens.kt`, androidx-main, cross-checked against specs-page text)
| Attribute | Linear | Circular |
| --- | --- | --- |
| Track/active thickness (default) | 4dp | 4dp |
| Container height / size (default) | 4dp | 40dp |
| Wavy container height | 10dp (`WaveHeight`) | 48dp (`WaveSize`) |
| Active wave amplitude | 3dp | 1.6dp |
| Active wave wavelength (determinate) | 40dp | 15dp |
| Indeterminate active wave wavelength | 20dp | n/a (token not present) |
| Stop indicator size | 4dp (circle) | n/a — "not used for indeterminate or circular progress indicators" |
| Gap between track and active indicator | 4dp | 4dp |
| Screen-edge inset (linear only) | 4dp | n/a |
Shape: active indicator, track, and stop indicator are all `CornerFull` (fully rounded ends) per `ProgressIndicatorTokens.kt`.
Color roles (specs page + `ProgressIndicatorTokens.kt`): active indicator & stop indicator = **Primary**; track = **Secondary container**.
Stop indicator rule (guidelines + accessibility pages): a 4dp circle marking the end of a **linear, determinate** indicator, required specifically when the track has **<3:1 contrast** with its container/surface; only omit it once contrast is confirmed ≥3:1.
Wait-time recommendation (verbatim table, guidelines page):
| Expected wait time | Recommendation |
| --- | --- |
| Instant (under 200ms) | No indicator |
| Short (between 200ms and 5s) | Loading indicator |
| Long (over 5s) | Progress indicator |
### Behaviour and guidelines (Google's wording)
- Use to show status of an ongoing process (app loading, form submit, saving). Show **one** indicator per group of loading items — don't add a separate indicator per activity in the group.
- **Linear** works best on the edge of a container; **circular** works best centered in an element. Keep the same variant for the same process everywhere in the product (e.g. don't mix circular/linear for the same "refresh" action across screens).
- **Determinate** (known progress/time) must accurately track real progress, filling 0-100%. **Indeterminate** (unknown progress/time) grows/shrinks along a fixed track repeatedly. A process should switch from indeterminate → determinate once real progress data becomes available.
- At very low percentages, the active indicator should render as a dot so users still perceive progress underway.
- Shape options: **flat** (default) or **wavy** — wavy suits longer or more "expressive" processes and increases the component's overall height; may be less visible at very small sizes.
- Animation direction: linear animates leading→trailing edge; circular animates clockwise from the top by default.
- Placement: put a linear indicator along the edge of the loading container (the edge that animates, if the container reshapes) or in its middle; use one indicator at the top of the page for whole-page loads, not one per element (unless each activates independently).
### Accessibility
- Assistive tech must be able to navigate to the indicator and understand what progress it communicates.
- Contrast: active indicator ≥**3:1** against most backgrounds; when embedded in another component (e.g. a button), the active indicator should match the label/icon color and the **track should be removed** in that context.
- Stop indicator requirement ties directly to the 3:1 rule (see Specs) — only drop it once contrast is verified.
- Role: **progressbar**. Labeling: describe the process + affected content, e.g. "Loading news article," "Refreshing page," "Loading my episodes" — applies to both determinate and indeterminate indicators.
### Source URLs
- https://m3.material.io/components/progress-indicators/overview (4687 bytes)
- https://m3.material.io/components/progress-indicators/guidelines (10003 bytes)
- https://m3.material.io/components/progress-indicators/specs (5676 bytes)
- https://m3.material.io/components/progress-indicators/accessibility (8843 bytes)
- Token files: LinearProgressIndicatorTokens.kt, CircularProgressIndicatorTokens.kt, ProgressIndicatorTokens.kt (androidx/androidx, androidx-main)
## Loading indicator
**Status**: New component, **M3 Expressive only** (added May 2025). No M3-baseline availability. Recommended as the replacement for the indeterminate circular progress indicator, and for pull-to-refresh.
### Anatomy
1. Active indicator (a shape that morphs to capture attention)
2. Container (optional; a circle behind the indicator for extra contrast)
### Variants and configurations (verbatim tables, source: specs page)
| Variant | M3 | M3 Expressive |
| --- | --- | --- |
| Loading indicator | -- | Available |
| Category | Configuration | M3 | M3 Expressive |
| --- | --- | --- | --- |
| Containment | Default | -- | Available |
| | Contained | -- | Available |
### Specs (numbers; source: specs page text + `LoadingIndicatorTokens.kt`, androidx-main)
| Attribute | Value |
| --- | --- |
| Container size (H×W) | 48dp |
| Active-indicator (shape) size | 38dp |
| Container shape | Full (circular) |
| Default color | Active = Primary |
| Contained colors | Active = On primary container; Container = Primary container |
| Responsive size range | 24dp 240dp (default 48dp is for mobile/compact; scale up for larger windows, ratio between container and active shape stays fixed) |
Note: 48dp container vs. 38dp active shape leaves an ~5dp margin on each side "to ensure sufficient margins" (site wording).
### Behaviour and guidelines (Google's wording)
- Use animation to grab attention, mask perceived latency, and signal an activity is in progress — for processes where progress isn't measurable or doesn't need a duration shown.
- Better alternative than a circular progress indicator specifically for **short waits, 200ms-5s** (see the shared wait-time table under Progress indicators: instant <200ms = no indicator, short 200ms-5s = loading indicator, long >5s = progress indicator).
- Don't transition a loading indicator into a determinate progress indicator — only indeterminate→determinate progress-indicator transitions are supported; a loading indicator is a dead end (it either finishes or stays a loading indicator).
- Active indicator morphs shape while animating, to capture attention.
- Container: make it visible (switching indicator color from Primary to On-primary-container) whenever the indicator sits over other content, for contrast; skip the container when it's directly on a plain surface. **Always use the container with pull-to-refresh.**
- Placement: center on the page/container being loaded; when appending more items to existing content, place it in the empty space reserved for new content (don't overlap existing content). Can be embedded in other components like buttons for actions that take a few seconds.
- Responsive: default 48dp, flexible from 24dp to 240dp — never exceed that range; scale up for large/extra-large windows (e.g. desktop) while keeping the container:shape size ratio fixed.
- Pull-to-refresh (Jetpack Compose only): best for dynamic content (lists/grids/cards) likely to have fresh content; the gesture must clear a **threshold** before triggering refresh (reversing past the threshold cancels it); indicator stays visible until the refresh completes or the user navigates away — don't let it scroll off-screen mid-refresh (implies the refresh is scoped to one component, not the whole screen).
### Accessibility
- Assistive tech must be able to: navigate to the indicator, understand what progress it communicates, and **initiate a content refresh without relying on the pull gesture**.
- Contrast: active indicator ≥**3:1** against the background/container/surface (the container itself has no contrast requirement); when embedded in another component (e.g. a button), the indicator needs ≥3:1 against that component too.
- Because pull-to-refresh can't be triggered by swipe alone accessibly, always provide an alternate single-pointer way to refresh (e.g. a refresh button in a menu or alongside the content, such as in an app bar).
- Role: **progress bar**. Labeling: describe the purpose, e.g. "loading news article," "refreshing page."
### Source URLs
- https://m3.material.io/components/loading-indicator/overview (2551 bytes — short but complete, new/small component page)
- https://m3.material.io/components/loading-indicator/guidelines (7193 bytes)
- https://m3.material.io/components/loading-indicator/specs (8699 bytes)
- https://m3.material.io/components/loading-indicator/accessibility (3310 bytes)
- Token file: LoadingIndicatorTokens.kt (androidx/androidx, androidx-main)
## Snackbar
**Status**: M3 available. Overview page has no "M3 Expressive update" section — no expressive-era changes noted. Not deprecated. Note: Material Web "doesn't yet include the snackbar component" per the site's own accessibility page (2023-era note; may be stale).
### Anatomy
1. Container
2. Icon (optional close affordance) — specs page lists this, though guidelines page anatomy instead lists "Close button (optional)" in the same slot
3. Supporting text
4. Action (optional, single text button)
### Variants and configurations
No verbatim variant/configuration table published (specs page uses only an interactive token browser). Configurations shown as image-only "5 snackbar configurations": single line; single line with action; two lines; two lines with action; two lines with longer action (action wraps to a third line).
### Specs (numbers; source `SnackbarTokens.kt`, androidx-main, since the specs page publishes no measurement text — only diagrams)
| Attribute | Value |
| --- | --- |
| Single-line container height | 48dp |
| Two-line container height | 68dp (token) — guidelines page prose instead says snackbars "expand vertically from 48dp to 64dp"; **discrepancy noted, verify against current token release** |
| Container shape | ExtraSmall (4dp corner radius) |
| Container elevation | Level3 (6dp) |
| Icon size | 24dp |
| Action label typography | Label large |
| Supporting text typography | Body medium |
| Margin from screen edge (material-components-android `Snackbar.md`) | 8dp |
| Elevation (material-components-android `Snackbar.md`, cross-check) | 6dp — matches Level3 |
Color roles (specs page): container = **Inverse surface**; supporting text/icon = **Inverse on surface**; action label = **Inverse primary**. Container must be **fully opaque** (guidelines: "so that text labels remain legible"; slight transparency is only a "Caution"-level allowance, not a default).
Duration: no exact milliseconds published on m3.material.io. Accessibility page states "common acceptable durations are **4-10 seconds**" for auto-dismiss, noting each platform sets its own requirement. Android's `Snackbar` class (material-components-android docs) exposes qualitative presets only: `LENGTH_SHORT`, `LENGTH_LONG`, `LENGTH_INDEFINITE` — no fixed dp/ms values documented there either.
### Behaviour and guidelines (Google's wording)
- Snackbars inform users of a process the app has performed or will perform; they're low-priority, non-interruptive, and people can keep browsing without engaging them.
- **Only one snackbar visible at a time.**
- Can carry a **single** action (e.g. "Undo"); "Dismiss"/"cancel" actions are unnecessary since snackbars disappear on their own by default (explicit Caution against adding a redundant dismiss action).
- Choose snackbar vs. dialog by priority/required-action:
| Component | Priority | User action |
| --- | --- | --- |
| Snackbar | Low priority | Optional — disappears automatically |
| Dialog | High priority | Required — blocks app usage until a dialog action or exit |
- Text label: short, directly related to the process; up to **two lines** on compact breakpoints; keep to one line when possible. Avoid icons in a snackbar (use a dialog instead if an icon feels necessary); avoid stylized text/inline links (use a button, or a different component, if a link is needed).
- Action styling: must use a **text button** with colored text distinct from the supporting-text color; never a filled/elevated button (too much visual weight). A long action can wrap to a third line.
- Placement: bottom of the UI, in front of main content; nudge upward to avoid overlapping FABs/docked toolbars; never place in front of frequently used touch targets or navigation. Snackbars should appear **above** FABs — never in front of or behind one. Can span full width only when the UI has no persistent nav components (app bar/nav bar); a full-width snackbar can push a FAB upward when it appears.
- Responsive: compact breakpoint — fixed distance from leading/trailing/bottom edges, height expands 48→64dp (site prose) for one/two lines. Medium/expanded breakpoints — scale horizontally for longer text (ideal line length ~40-60 characters), flexible distance from the trailing edge, and aim for a single line + optional button where possible.
- Accessibility-driven design requirement (also in guidelines): on web, since auto-dismissing snackbars are hard to perceive for low-vision users or those needing more time, either (1) mirror the snackbar's message as inline feedback near the triggering action (e.g. a "Save" button relabels to "Saved"), or (2) make the snackbar actionable so it doesn't auto-dismiss.
### Accessibility
- Users must be able to: be alerted without being disrupted, move focus to an actionable snackbar, and act on it via assistive tech.
- **Snackbars with an action must never auto-dismiss** — let people read/act at their own pace; snackbars without actions may auto-dismiss (common range **4-10 seconds**), platform rules vary.
- Contrast/color: use the default (inverse) color mapping to stand out reliably.
- Focus: appearing announces the message but **never moves focus**; never trap focus inside the snackbar (must remain freely navigable in/out); on web, provide a documented keyboard shortcut (e.g. Alt+G) to jump focus to a snackbar with an action. On dismiss, focus should return to the triggering element or the next logical element (Android Compose may fall back to the nearest visible/first actionable item).
- Keyboard: Tab moves between interactive elements; **Esc dismisses the focused snackbar**.
- Announcement: use a **live region with a "polite"/queued** announcement (not assertive) on Android and web; iOS 17+ defaults to polite announcements too. A snackbar shown at app launch should announce after the page title, without taking focus.
### Source URLs
- https://m3.material.io/components/snackbar/overview (1728 bytes — short but complete, genuine small page)
- https://m3.material.io/components/snackbar/guidelines (18942 bytes)
- https://m3.material.io/components/snackbar/specs (7490 bytes)
- https://m3.material.io/components/snackbar/accessibility (9606 bytes)
- Token file: SnackbarTokens.kt, ElevationTokens.kt (androidx/androidx, androidx-main)
- material-components-android docs: Snackbar.md (margin/elevation/duration-preset cross-check)
## Tooltips
**Status**: M3 available. No "M3 Expressive update" section on the overview page — no expressive-era changes. Not deprecated.
### Anatomy
Plain tooltip: 1. Container, 2. Supporting text.
Rich tooltip: 1. Subhead (optional), 2. Container, 3. Supporting text, 4. Text button(s) (optional, up to two).
### Variants and configurations
Two variants: **plain** (brief label for elements with no text, e.g. icon-only buttons/fields) and **rich** (longer context — definitions/explanations; optional subhead, up to two text buttons, hyperlinks). Rich tooltip common configurations (site, specs page): subhead+text+2 buttons; subhead+text+1 button; subhead+text only; text+1 button; text+2 buttons.
### Specs (verbatim tables, source: specs page)
Plain tooltip:
| Attribute | Value |
| --- | --- |
| Container height | 24dp |
| Padding | 8dp |
Rich tooltip:
| Attribute | Value |
| --- | --- |
| Top padding | 12dp |
| Bottom padding | 8dp |
| Left and right padding | 16dp |
Cross-check / additions from `PlainTooltipTokens.kt` / `RichTooltipTokens.kt` (androidx-main, not shown as text on the site):
| Attribute | Plain | Rich |
| --- | --- | --- |
| Container shape | ExtraSmall (4dp) | Medium (12dp) |
| Container elevation | none | Level2 (3dp) |
| Container color | Inverse surface | Surface container |
| Supporting text color | Inverse on surface | On surface variant |
| Supporting text font | Body small | Body medium |
| Subhead color/font | n/a | On surface variant / Title small |
| Action label color/font | n/a | Primary / Label large |
Placement distances (guidelines page): plain tooltip sits **4dp** from a target with a visible boundary (e.g. a button) or **8dp** from one without (e.g. text baseline); in an app bar, the tooltip flips to appear *below* the element at the same distance. Rich tooltip defaults to bottom-right of its parent and repositions in **8dp increments** to stay on screen.
Timing: tooltips are **transient by default** — both plain and rich tooltips disappear **1.5 seconds** after the cursor/focus leaves the target region; opening a new tooltip immediately closes any other open one (only one tooltip visible at a time).
### Behaviour and guidelines (Google's wording)
- Plain tooltips: use to label icon-only buttons/fields; don't add one when the element already shows label text (redundant).
- Rich tooltips: use for extra info/actions about an element or a new feature; never hide **critical** information in a tooltip — use an interruptive dialog instead for anything that matters.
- Subhead: keep to one line, summarizing the message; especially important when the tooltip appears automatically (e.g. on page load). Buttons: up to two, short enough to sit side by side — avoid stacking them.
- Trigger: hover on desktop, or tap-and-hold on mobile, opens a normal tooltip. **Persistent rich tooltips** open only via click/tap on the parent, or automatically on page load to explain a new feature — hovering never triggers a persistent tooltip. Persistent tooltips stay open even after leaving the target region and close only when the user interacts with another UI element. Avoid persistent rich tooltips on icon buttons.
- Desktop rich tooltips may center below the parent and stay visible while the pointer moves within the target region.
### Accessibility
- Assistive tech must be able to receive the tooltip's message and activate it via keyboard/switch input.
- Non-required-action tooltips must stay on screen long enough to be read without disrupting the user's flow.
- Tooltips can appear on hover **or focus** for an actionable element (button, nav rail item, etc.) — must never hide crucial info that way. Rich tooltips can also open via selecting the element rather than hover/focus.
- Focus order inside a rich tooltip moves **top to bottom** through its interactive elements (e.g. parent element → inline link → text button); never trap screen-reader/keyboard focus inside the tooltip — people must still be able to move linearly through the rest of the page.
- Keyboard: Tab lands on the tooltip's button if one exists; Space or Enter activates the focused element.
- Role: **Tooltip** (or an equivalent role) on the container; every element inside follows its own component's accessibility labeling guidance.
### Source URLs
- https://m3.material.io/components/tooltips/overview (7060 bytes)
- https://m3.material.io/components/tooltips/guidelines (10230 bytes)
- https://m3.material.io/components/tooltips/specs (5228 bytes)
- https://m3.material.io/components/tooltips/accessibility (3199 bytes)
- Token files: PlainTooltipTokens.kt, RichTooltipTokens.kt, ElevationTokens.kt, ShapeTokens.kt (androidx/androidx, androidx-main)
## Bottom sheets
**Status**: M3 available. No "M3 Expressive update" section on overview — no expressive-era changes noted. Not deprecated.
### Anatomy
1. Container (only required element)
2. Drag handle (optional)
3. Scrim (modal only)
Optional content inside: list items, dividers, media (thumbnail/image/video).
### Variants and configurations
Two variants: **standard** (coexists with main UI, doesn't block interaction — e.g. an audio player) and **modal** (appears in front of app content, blocks other functionality until confirmed/dismissed/a required action is taken — like a dialog). Modal bottom sheets are **mobile-only**. Use in **compact and medium** breakpoints. No verbatim variant/configuration table is published (specs page uses only an interactive token browser plus prose/diagrams).
### Specs (verbatim table, source: specs page)
| Attribute | Value |
| --- | --- |
| Drag handle alignment (horizontal) | Center |
| Drag handle padding top/bottom | 22dp |
| Top margin | 72dp |
| Top margin (window width > 640dp) | 56dp |
| Start/end margin (window width > 640dp) | 56dp |
| Width | Full width, up to max-width 640dp |
| Height | Variable |
Additional numbers from the overview page: **28dp top corner radius**; new (vs. M2) **640dp max-width**; drag handle has an accessible **48dp hit target**.
Cross-check / additions, source `SheetBottomTokens.kt` (androidx-main): `DockedContainerShape` = CornerExtraLargeTop (28dp top corners, square bottom — matches "28dp top corner radius"); `DockedDragHandleHeight` = 4dp, `DockedDragHandleWidth` = 32dp; `DockedMinimizedContainerShape` = CornerNone; `DockedModalContainerElevation` / `DockedStandardContainerElevation` = Level1 (1dp).
Color roles (specs page): Scrim (system-handled opacity/color on Android); drag handle = On surface variant; container = Surface container low.
Touch target: the **top 48dp** of the sheet is interactive for resize when a drag handle is present and user resizing is available.
### Behaviour and guidelines (Google's wording)
- Content should be supplementary/secondary — never the app's primary content; a sheet can be dismissed to return to the main content.
- **Standard**: use for content that complements the primary screen while both remain usable (e.g. music player controls while browsing albums); at full-screen height a standard sheet shows a collapse icon in its app bar to return to its initial position; can show content that "continues below the screen" (e.g. location info over a map).
- **Modal**: use as an alternative to inline menus or simple dialogs on mobile, especially for long action lists or items needing longer descriptions/icons. Initial vertical position is **capped at 50% of screen height**; if content exceeds that, it can be pulled to full screen and scrolled internally. Triggered by a user action (button/overflow icon); dismissible by: tapping a menu item/action inside it, tapping the scrim, swiping down, or a close affordance in its app bar (required for a full-screen modal sheet).
- Custom positioning: the drag handle can be dragged **or selected** to cycle through preset heights, and sheets must be closeable without dragging; selecting the drag handle toggles preset heights or closes the sheet, selecting the scrim always closes it. If multiple preset heights exist but a drag handle can't be used, Material **requires** a single-pointer (non-drag) alternative to change height.
- Responsive: compact breakpoint — full screen width, elevated above primary content. Medium/expanded — default max-width (overridable) to avoid awkward spacing; for complex flows consider a non-transient "floating sheet" instead. On larger expanded breakpoints (desktop), a bottom sheet can be swapped for a **side sheet** showing equivalent content.
### Accessibility
- Touch target: reserve the sheet's **top 48dp** for resize interactions when a drag handle is present.
- Initial focus: the (optional) drag handle is focusable in tab order and operable via keyboard/switch controls.
- Dragging: any drag-only action needs a **single-pointer alternative**; the drag handle should cycle through available heights when activated (not just dragged) — if a drag handle can't be used at all, add a button that performs the same cycling.
- Keyboard: Tab focuses the drag handle; Space/Enter toggles between available heights.
- Labeling: label **only the drag handle**; its accessibility role is **"button."** (The container/content follow their own components' guidance.)
### Source URLs
- https://m3.material.io/components/bottom-sheets/overview (6877 bytes)
- https://m3.material.io/components/bottom-sheets/guidelines (17231 bytes)
- https://m3.material.io/components/bottom-sheets/specs (3672 bytes)
- https://m3.material.io/components/bottom-sheets/accessibility (3913 bytes)
- Token file: SheetBottomTokens.kt, ElevationTokens.kt, ShapeTokens.kt (androidx/androidx, androidx-main)
## Cards
**Status**: M3 available. No "M3 Expressive update" section on overview — no expressive-era changes noted. Not deprecated. Web implementation is explicitly **"Unavailable"** on the resources table (Flutter and Android/Compose are Available).
### Anatomy
1. Container (only required element; also expresses elevation)
2. Image
3. Button
4. Supporting text
5. Subhead
6. Headline
Optional additions: dividers (full-width for expandable content, inset for separating related content), media (thumbnail/image/video), icon buttons, selection controls (chips/sliders/checkboxes), linked text, overflow menu (usually upper-right or lower-right corner).
### Variants and configurations
Three variants, differing only in emphasis/style (same legibility & functionality): **elevated** (drop shadow — more separation than filled, less than outlined), **filled** (subtle separation, least emphasis), **outlined** (visual boundary/stroke — most emphasis of the three). No verbatim variant/configuration table published (specs page is organized as three prose+diagram sections, one per variant, plus a measurements table).
### Specs (verbatim table, source: specs page)
| Attribute | Value |
| --- | --- |
| Shape | 12dp corner radius |
| Left/right padding | 16dp |
| Padding between cards | 8dp max |
| Label text alignment | Start-aligned |
Color roles per variant (specs page): Elevated = **Surface container low**; Filled = **Surface container highest**; Outlined = **Surface** container + **Outline variant** border.
Cross-check / additions, source `ElevatedCardTokens.kt` / `FilledCardTokens.kt` / `OutlinedCardTokens.kt` (androidx-main — elevation-per-state and outline width aren't shown as text on the site):
| Attribute | Elevated | Filled | Outlined |
| --- | --- | --- | --- |
| Corner shape | Medium (12dp) | Medium (12dp) | Medium (12dp) |
| Rest elevation | Level1 (1dp) | Level0 (0dp) | Level0 (0dp) |
| Hover elevation | Level2 (3dp) | Level1 (1dp) | Level1 (1dp) |
| Focus/Pressed elevation | Level1 (1dp) | Level0 (0dp) | Level0 (0dp) |
| Dragged elevation | Level4 (8dp) | Level3 (6dp) | Level3 (6dp) |
| Disabled container opacity | 0.38 | 0.38 | n/a (uses disabled outline opacity 0.12 instead) |
| Outline width | n/a | n/a | 1dp |
| Icon size (any embedded icon) | 24dp | 24dp | 24dp |
States shown on specs page for all three variants: Hovered, Focused, Pressed, Dragged, Disabled.
### Behaviour and guidelines (Google's wording)
- Use cards to display content and actions about a single subject; they can serve as entry points into deeper detail/navigation (e.g. an album or a trip's details).
- Display cards together in a **grid, vertical list, or carousel**. Don't force content into cards when simple spacing/headlines/dividers would give a clearer hierarchy (explicit Don't).
- Card container is the only required element — everything else (image, headline, subhead, supporting text, buttons) is optional and the card sizes itself to its content.
- Layering text/icons on images is **not recommended**; if necessary, add a translucent scrim or a bounding shape behind the text/icon to guarantee accessible contrast.
- Actions: a card is either a **non-actionable container** holding its own buttons/links, or **directly actionable** as a whole (no internal buttons/links) — never stack an action on top of an already-actionable surface.
- Cards in a collection share the same **resting elevation** by default (coplanar) unless one is picked up/dragged.
### Accessibility
- Touch: a directly-actionable card ripples on tap; non-actionable cards never ripple.
- Cursor: a directly-actionable card shows a hover state; non-actionable cards have none. Click produces a ripple on directly-actionable cards.
- Dragging/dismissing: any drag/swipe interaction (e.g. reordering, dismiss) needs a **single-pointer alternative** — e.g. tap or press-and-hold opens a menu with the same reorder/delete actions. Avoid placing a menu on top of a card while it's in a draggable state; if unavoidable, make sure the interaction can still be completed (menu shouldn't fully obscure the card).
- Keyboard: Tab moves to the next actionable element — on a **directly actionable card** Tab moves to the next card container; on a **non-actionable card with actionable elements**, Tab moves through each actionable element inside before moving to the next card. Space/Enter confirms the action (may trigger a secondary menu, navigable with Arrow keys, Space/Enter to select, Tab to exit).
- Focus: every interactive element needs a tab stop. A directly-actionable card is itself a tab stop; a non-actionable card is not, but every actionable element inside it is (all visited before moving to the next card).
- Labeling: card content is verbalized when a screen reader reaches it; hide purely decorative images from screen readers. Directly actionable cards get a **button** or **link** role depending on usage; non-actionable cards (pure containers) need **no role**.
### Source URLs
- https://m3.material.io/components/cards/overview (7742 bytes)
- https://m3.material.io/components/cards/guidelines (24196 bytes)
- https://m3.material.io/components/cards/specs (5636 bytes)
- https://m3.material.io/components/cards/accessibility (7001 bytes)
- Token files: ElevatedCardTokens.kt, FilledCardTokens.kt, OutlinedCardTokens.kt, ElevationTokens.kt, ShapeTokens.kt (androidx/androidx, androidx-main)
## Carousel
**Status**: New in M3 (no M2 equivalent — "This component is new in Material 3"). Uses an "Updates" section rather than "M3 Expressive update": **2023** added Uncontained, Full-screen, Centered/Hero, Multi-browse layouts; **November 2025** added the **Uncontained multi-aspect ratio** layout. Not deprecated. Note: androidx Compose Material3 tokens have no dedicated `CarouselTokens.kt` file — all numeric specs below come directly from the m3.material.io specs page text.
### Anatomy
1. Container (a rectangle, stretchable to any size, holding all items)
2. Large carousel item
3. Medium carousel item
4. Small carousel item (width range 40-56dp, dynamic)
### Variants and configurations
Six layouts, each with a recommended use (verbatim table, guidelines page):
| Layout | Best used for |
| --- | --- |
| Multi-browse | Browsing many visual items at once (like photos), dynamic designs |
| Uncontained | Highly-customized or text-heavy carousels, stacked image and text, traditional carousel behavior |
| Hero | Spotlighting very large visual items (like a movie or featured app) |
| Center-aligned hero | Centered, large visual items |
| Full-screen | Vertically-scrolling video or image feeds, immersive experiences |
(Uncontained multi-aspect-ratio is the 6th layout, added Nov 2025 — same as Uncontained but items vary in width, ranging from a 9:16 minimum to a 16:9 maximum aspect ratio; "only use this layout if the items have various widths.")
Scrolling modes: **Default** (standard scroll, recommended for Uncontained) vs. **Snap-scrolling** (items snap to the layout; recommended for Multi-browse, Hero, and Full-screen). Full-screen must use snap-scrolling — never default scrolling.
### Specs (verbatim tables per layout, source: specs page)
| Layout | Alignment | Leading/trailing padding | Top/bottom padding | Padding between elements | Item corner radius | Item widths |
| --- | --- | --- | --- | --- | --- | --- |
| Multi-browse | Vertically centered | 16dp | 8dp | 8dp | 28dp | Large: dynamic/user-set; Medium: dynamic; Small: 40-56dp |
| Uncontained | Vertically centered | 16dp (leading only) | 8dp | 8dp | 28dp | n/a (single size, bleeds past padding on scroll) |
| Uncontained multi-aspect ratio | Vertically centered | 16dp (leading only) | 8dp | 8dp | 28dp | Various, 9:16 min to 16:9 max |
| Hero | Vertically centered | 16dp | 8dp | 8dp | 28dp | Large: dynamic; Small: 40-56dp |
| Center-aligned hero | Vertically centered | 16dp | 8dp | 8dp | 28dp | Large: dynamic; Small: 40-56dp |
| Full-screen | Centered | 0dp | 0dp | 16dp | (edge-to-edge, no item radius given) |
General item-width rule (specs page): small carousel items have a **minimum width of 40dp and a maximum width of 56dp**; large items have a customizable max width; all item types resize dynamically with the container/breakpoint.
Accessibility-affordance sizing (accessibility page): "Show all" button padding = **4dp**; header-adjacent arrow icon button size = **48dp**.
Color roles (specs page): Container; Surface. States shown: Enabled, Hovered, Focused, Pressed, Disabled.
### Behaviour and guidelines (Google's wording)
- Carousel items must be **fully visible on screen** (exception: the Uncontained layout, whose items intentionally bleed past the edge padding). Items automatically resize and **snap into place** on scroll to preserve layout.
- Don't set items so small the image becomes unrecognizable — large items in particular "must remain big enough to be easy to understand and recognize."
- At **compact** breakpoints, show at most **three** items if they carry text; showing more than three is only a Caution-level allowance, and only if content stays easy to recognize without text.
- Per-layout guidance: Multi-browse avoids heavy text/complex imagery; Uncontained suits highly customized/text-heavy content since item size doesn't change; Full-screen only works in **portrait** at compact/medium breakpoints — never landscape, and must snap-scroll.
- Center-aligned hero = hero layout with an extra small item on the leading edge so the large item sits centered (two small items flank one large, centered item).
- Vertically-scrolling pages: a carousel needs an accessible way to view all items without horizontal scrolling (this requirement doesn't apply to full-screen carousels). Recommended solution: a **"Show all"** button below the carousel opening a dedicated vertical list of all items; if the carousel has a header, an arrow icon button beside the header can substitute. Don't place navigation arrows/icons inside or overlapping the carousel itself — put any such control above or below it.
### Accessibility
- Assistive tech must be able to: navigate to the carousel container, navigate between items, activate an item, and **skip over** the carousel entirely.
- Initial focus: Tab places focus on the **first carousel item** directly (never the container itself — explicit Don't); Tab or Arrow keys then move between items; Up/Down arrows exit the carousel to the next page element (e.g. the "Show all" button).
- Keyboard: Tab or Arrow keys move to the previous/next item; Space or Enter activates the focused item.
- Roles/labeling: the carousel container has the **container** role; each item's label announces the current item position and total count (e.g. "item 3 of 10").
- Touch/cursor: tapping an item slightly changes its shape and ripples; hovering shows a hover cue; clicking ripples in both active and inactive states.
- Reduced motion: when enabled, remove the parallax effect and stop items expanding as they scroll into view — all items become the same size, and the carousel must still reach the window edges to avoid clipping. In a reduced-motion hero carousel, the small item shows only partially.
### Source URLs
- https://m3.material.io/components/carousel/overview (4697 bytes)
- https://m3.material.io/components/carousel/guidelines (16106 bytes)
- https://m3.material.io/components/carousel/specs (9478 bytes)
- https://m3.material.io/components/carousel/accessibility (7515 bytes)
- No androidx Compose Material3 token file exists for carousel; all numbers above are from the m3.material.io specs page text.
## Dialogs
**Status**: M3 available. No "M3 Expressive update" section on overview — no expressive-era changes noted. Not deprecated.
### Anatomy
Basic dialog: 1. Container, 2. Icon (optional), 3. Headline (optional), 4. Supporting text, 5. Divider (optional), 6. Button label text, 7. Scrim.
Full-screen dialog: 1. Container, 2. Header region, 3. Icon (close affordance), 4. Headline (optional), 5. Button label text, 6. Divider (optional).
### Variants and configurations
Two variants: **basic** (interrupts with urgent info/details/actions — alerts, quick selection, confirmation; also hosts date/time pickers) and **full-screen** (fills the entire screen for a multi-step task, e.g. creating a calendar entry). No verbatim variant/configuration table is published (specs page is organized per-variant with prose+diagrams plus measurement tables).
### Specs (verbatim tables, source: specs page)
Basic dialog:
| Attribute | Value |
| --- | --- |
| Container shape | 28dp corner radius |
| Container height | Dynamic |
| Container width | Min 280dp; Max 560dp |
| Divider height | 1dp |
| Icon size | 24dp |
| Alignment with icon | Center-aligned |
| Alignment without icon | Start-aligned |
| Top/left/right/bottom padding | 24dp |
| Padding between buttons | 8dp |
| Padding between title and body | 16dp |
| Padding between icon and title | 16dp |
| Padding between body and actions | 24dp |
Full-screen dialog:
| Attribute | Value |
| --- | --- |
| Container shape | 0dp corner radius |
| Container height | Dynamic |
| Container width | Container width; Max 560dp |
| Header height | 56dp |
| Header width | Container width |
| Headline text alignment | Start-aligned |
| Divider height | 1dp |
| Icon (close affordance) size | 24dp |
| Bottom action bar height | 56dp |
| Bottom action bar width | Container width |
| Top/left/right padding | 24dp |
| Padding between elements | 8dp |
Custom positioning on larger screens must respect a **56dp margin** from screen edges (guidelines page).
Color roles — basic dialog (specs page): Surface container high (container), Secondary (icon), On surface (headline), On surface variant (supporting text), Primary (button label), Scrim. Full-screen dialog: Surface container high, On surface (×2 roles), Primary, On surface variant.
Cross-check, source `DialogTokens.kt` (androidx-main): `ContainerColor` = SurfaceContainerHigh, `ContainerElevation` = Level3 (6dp), `ContainerShape` = ExtraLarge (28dp, matches site), `HeadlineFont` = HeadlineSmall, `SupportingTextFont` = BodyMedium, `ActionLabelTextFont` = LabelLarge.
### Behaviour and guidelines (Google's wording)
- A dialog is a modal window in front of app content for critical info or a required decision; it disables all other app functionality and stays until confirmed/dismissed/a required action is taken. Purposefully interruptive — use sparingly; a dropdown menu is a less disruptive alternative when appropriate.
- Choose dialog vs. snackbar by importance:
| Component | Importance | Action needed |
| --- | --- | --- |
| Snackbar | Low importance | Optional — may have no button, can disappear automatically |
| Dialog | High importance | Required — blocks main content until an action is confirmed |
- Headline: brief, clear statement or question; avoid apologies ("Sorry for the interruption"), alarm ("Warning!"), or ambiguity ("Are you sure?"). Can wrap to a second line or truncate; in full-screen dialogs, move long/variable-length headlines into the content area instead of the app bar if truncation would confuse.
- Buttons: aligned to the **trailing edge**; the confirmation button sits closest to the edge (mirrors to the left edge in RTL). Disable the confirming action until a required choice is made — **dismissive actions are never disabled**. Don't place a dismissive action to the right of a confirming one — dismissive goes to the left of confirming. A single action button is only acceptable for a pure acknowledgement.
- Full-screen dialog specifics: is the **only** dialog type another dialog can appear above (since it fills the whole screen); used only in **compact** breakpoints (use basic dialogs at medium/expanded instead); appropriate when the dialog needs keyboard input (form fields), changes aren't saved instantly, or its components open further dialogs. Save = "Save"; dismiss = close icon, "Cancel," or "Back." Confirmation label must state what happens next (e.g. "Send," "Create") — avoid vague labels like "Done"/"OK"/"Close," never disable the confirm button, and only show a follow-up basic dialog if the action **fails**. Dismissing with unsaved changes must trigger a basic dialog confirming the discard. Inline field errors show next to the field; general errors (e.g. network failure) show in a basic dialog — show all errors on the page at once. The app bar's only navigation control should be the close "X" icon.
- Adaptive: a full-screen dialog can become a basic dialog at larger breakpoints. Medium breakpoint — basic dialogs default to centered, overridable for ergonomics. Expanded breakpoint — dialogs behave as modal windows above a scrim, calling full attention; custom-positioned dialogs must respect the 56dp edge margin.
- Motion: appears via an enter/exit transition. Dialogs retain focus until dismissed/actioned, and must not be obscured or shown partially on screen — except full-screen dialogs. Scrolling: dialog content generally shouldn't scroll; if it must, the title stays pinned at top and buttons pinned at bottom, and the dialog never scrolls with background content.
### Accessibility
- Use sparingly — interruption disrupts screen-reader flow; put non-critical info in the page flow instead of a dialog.
- 200% text size: headlines should fit within **4 lines** at 200% zoom on Android; if truncated, provide an alternate way to reach the full content in one tap.
- Elements inside a dialog (text fields, typography, buttons, etc.) follow their own components' accessibility guidance.
- Initial focus: lands automatically on the **first interactive element** in the dialog.
- Keyboard: Tab moves to the next interactive element (wraps to first from the last); Shift+Tab moves to the previous (wraps to last from the first); Space/Enter triggers the focused element's action; **Escape closes the dialog**.
- Labeling: the dialog's accessibility label is typically its title/headline. On web, a basic dialog uses the **alert dialog** role. Elements inside follow their own component's labeling guidance.
### Source URLs
- https://m3.material.io/components/dialogs/overview (7457 bytes)
- https://m3.material.io/components/dialogs/guidelines (25235 bytes)
- https://m3.material.io/components/dialogs/specs (5390 bytes)
- https://m3.material.io/components/dialogs/accessibility (7478 bytes)
- Token file: DialogTokens.kt, ElevationTokens.kt, ShapeTokens.kt (androidx/androidx, androidx-main)
## Divider
**Status**: M3 available. No "M3 Expressive update" section — no expressive-era changes noted. Not deprecated.
### Anatomy
A divider is a single simple line — one element.
### Variants and configurations
No formal named "variants" table; the guidelines describe divider **usages**: **full-width** (separates larger, unrelated sections; also separates interactive from non-interactive areas) and **inset** (separates related content within a section, indented from both edges, anchored near icons/avatars). A **vertical divider** variant separates side-by-side content (e.g. text vs. media) on larger screens. M2 added vertical dividers as a new capability (overview page differences-from-M2 section).
### Specs (verbatim table, source: specs page)
| Attribute | Value |
| --- | --- |
| Divider full-width | 100% |
| Divider inset left margin | 16dp |
| Divider inset right margin | 0dp |
| Divider middle-inset left margin | 16dp |
| Divider middle-inset right margin | 16dp |
| Space between divider & supporting text | 4dp |
| Divider right margin | 8dp |
| Divider bottom margin | 8dp |
Cross-check, source `DividerTokens.kt` (androidx-main — thickness not shown as text on the site): `Color` = Outline variant; `Thickness` = **1dp**.
Color role: Outline variant (specs page + token file, matches).
### Behaviour and guidelines (Google's wording)
- Dividers visually group components, build hierarchy, and can imply nested parent/child relationships.
- **Full-width**: use for larger sections of unrelated content, directly on a surface or inside components like cards/lists; also used to separate interactive from non-interactive areas. Use **sparingly** — too many divider lines make an interface look cluttered (explicit Caution).
- **Inset**: use for related content within one section (e.g. emails in a list); indented equally from both sides by default; pair with anchoring elements like icons/avatars and align to the leading edge.
- Combining both on one screen: full-width dividers should separate **different kinds of content** (sections), inset dividers should separate **nested/related items** within a section — using both together should reinforce that hierarchy, not blur it. Lists with repetitive item formats may skip dividers entirely and rely on margin alone.
- **Vertical divider**: useful for arranging content side-by-side on larger screens (e.g. text next to video/imagery).
### Accessibility
- Dividers are purely **decorative** — they carry **no contrast minimum** requirement, since the content they separate should already be distinguishable via type styles and spacing. No keyboard/focus/labeling guidance is given (the accessibility page is deliberately minimal, consisting of only this one statement).
### Source URLs
- https://m3.material.io/components/divider/overview (2124 bytes — short but complete, genuine small page)
- https://m3.material.io/components/divider/guidelines (7319 bytes)
- https://m3.material.io/components/divider/specs (6808 bytes)
- https://m3.material.io/components/divider/accessibility (5112 bytes)
- Token file: DividerTokens.kt (androidx/androidx, androidx-main)
## Lists
**Status**: M3 available; M3 Expressive update **December 2025** added a new **expressive** list variant (segmented style, improved selection states, flexible slots) — recommended for new designs. Baseline list variant still available but "not recommended" per the specs page's variant table. Web Expressive support is "Unavailable" (only Android Views and Jetpack Compose support expressive lists; on web, expressive lists are built on top of baseline lists).
### Anatomy
Container and label text are required; all others optional: 1. Container, 2. Overline, 3. Label text, 4. Trailing text, 5. Supporting text, 6. Trailing icon, 7. Divider, 8. Leading avatar, 9. Leading icon, 10. Leading media (image/video).
Slot model (expressive/custom lists): **Leading**, **Content** (must be the largest-width slot, centered), **Trailing** slots — leading/trailing must each be narrower than content.
### Variants and configurations (verbatim tables, source: specs page)
| Variants | M3 | M3 Expressive |
| --- | --- | --- |
| Lists (expressive) | -- | Available |
| Lists (baseline) | Available | Not recommended. Use expressive lists instead. |
| Category | Configuration | M3 | M3 Expressive |
| --- | --- | --- | --- |
| Styles | Standard | Available | Available |
| | Segmented | -- | Available |
| Selection modes | Single-action, multi-action, single-select, multi-select | Available | Available |
| Interactions | Expand, swipe* | Available | Available |
\* Swipe-to-reveal is only available on Android Views.
Standard vs. segmented is purely visual and doesn't affect behavior. A list has exactly one selection mode at a time (can't be both single- and multi-select simultaneously).
### Specs (numbers)
Height rule (overview page, "Differences from M2 to M3 baseline" — applies to expressive too per token cross-check): **the tallest element in a list item sets its height**, which is always **56dp** (one line), **72dp** (two lines), or **88dp** (three lines). Alignment: elements are middle-aligned by default; top-aligned if the item is 88dp+ or has 3+ lines of text.
Shape morphing on selection (specs page, cross-checked against `ListTokens.kt`, androidx-main): unselected item corner radius = **4dp inner** (`ItemContainerExpressiveShape` = ExtraSmall) / **16dp outer** (list `ContainerShape` = Large); selected item corner radius = **16dp all around** (`ItemSelectedContainerExpressiveShape`/`ItemSelectedContainerShape` = Large). Interaction-state expressive shapes: hovered = Medium (12dp); focused/pressed/dragged/selected-any-state = Large (16dp).
Additional numbers, source `ListTokens.kt` (androidx-main — not shown as text on the site):
| Attribute | Value |
| --- | --- |
| One-line container height | 56dp |
| Two-line container height | 72dp |
| Three-line container height | 88dp |
| Leading/trailing padding | 16dp |
| Item-to-item space (between-space) | 12dp |
| Item bottom space | 10dp |
| Divider leading/trailing space | 16dp |
| Divider top/bottom space | 0dp |
| Leading icon size (baseline / expressive) | 24dp / 20dp |
| Trailing icon size (baseline / expressive) | 24dp / 20dp |
| Leading avatar size | 40dp (shape Full/circular) |
| Leading image size | 56×56dp |
| Leading video (large) | 64dp × 114dp |
| Leading video (small) | 56dp × 100dp |
| Trailing supporting text font | Label small |
| Rest container elevation | Level0 (0dp) |
| Dragged container elevation | Level4 (8dp) |
| Disabled label/icon/overline/supporting-text opacity | 0.38 |
| Disabled state-layer opacity | 0.1 |
Color roles (specs page): 10 roles mapped across Surface, On surface (variant), Outline variant, Primary container/On primary container (selected state) for the expressive variant; the baseline variant uses 9 analogous roles (specs page).
States shown for both default and selected list items: Enabled, Disabled, Hovered, Focused, Pressed, Dragged.
Slot accessibility rule (specs page): slots are **not accessible by default**; any custom slot content must follow standard list item padding, keep a minimum **48×48dp** target size, and avoid interactive elements that make the item hard to navigate for screen-reader users.
### Behaviour and guidelines (Google's wording)
- Lists are vertical groups of text/icons/images optimized for reading comprehension; use for communicating or selecting discrete items (e.g. choosing a color).
- Keep visual anchoring/alignment **consistent** across items — don't vary element position row to row.
- Text can be label-only, or label + supporting text (1 or 2 lines); both may wrap or truncate.
- Selection modes (mutually exclusive per list): **Single-select** (radio-button-like; no multi-actions, no secondary nested actions, shouldn't use checkboxes); **Multi-select** (checkbox/switch-like; no secondary nested actions, shouldn't use radio buttons); **Single-action** (whole item performs one action, e.g. navigation; no secondary actions, can't hold a persistent selected state); **Multi-action** (a primary action plus one or more supplementary actions — primary action occupies most of the leading+content space, supplementary actions like bookmark/menu go in the trailing position); **Non-interactive** (pure information display, not selectable).
- Selection controls: **use only one selection interaction per list item** (explicit Don't against combining, e.g., a checkmark AND a separate bookmark toggle in the same item).
- Interactions: items containing nested items can **expand/collapse** (container-transform, expanding vertically across the whole screen on tap). On Android, items can be **swiped** to reveal action buttons — the primary action must be the final, end-aligned option, and a full swipe triggers it (clearing the item and other actions off-screen); always provide an alternate (non-swipe) way to reach hidden actions, e.g. a "more" icon.
### Accessibility
- Assistive tech must be able to navigate to and select a list item.
- **Never indicate selection with color alone** — pair it with a second cue: radio button/checkbox, a leading/trailing icon, or a non-color style like underlined text.
- Touch: tapping ripples. Cursor: hover shows a visible cue that the item is interactive.
- Keyboard/switch (single-action lists): Tab focuses the first item (or the already-selected item, if any); Arrow keys then move within the list; Space/Enter activates the focused item.
- Multi-action lists: Tab focuses the first action in the item; **Up/Down/Left/Right** arrows move between all focusable elements/actions (wrapping into neighboring items at the ends); Space/Enter activates the focused action. The list item itself is not selectable in this mode — only individual actions are.
- General keyboard table (accessibility page): Tab moves focus to the first item, last item, or out of the list; Down/Right arrow moves to the next element (wraps to top at the end); Up/Left arrow moves to the previous element (wraps to bottom at the start); Space/Enter selects an unselected item.
- Swipe alternative: any swipe-revealed action needs a single-pointer alternative (single tap, double tap, long press, etc.) — never swipe-only.
- Labeling: a list item's accessibility label is typically its **label text + supporting text**. Platform-specific role/state mapping (verbatim tables, accessibility page):
Single-select lists: Web → container role List box (label describes selection type), item role Option, state Selected/Not-selected. Android Views / Jetpack Compose → item role **Radio button**, state Checked/Not-checked.
Multi-select lists: Web → container role List box, item role Option, state Selected/Not-selected. Android Views / Jetpack Compose → item role **Checkbox**, state Checked/Not-checked.
### Source URLs
- https://m3.material.io/components/lists/overview (5095 bytes)
- https://m3.material.io/components/lists/guidelines (20938 bytes)
- https://m3.material.io/components/lists/specs (20786 bytes)
- https://m3.material.io/components/lists/accessibility (12204 bytes)
- Token file: ListTokens.kt, ExpandedListTokens.kt, ReorderListTokens.kt, RevealListTokens.kt, ShapeTokens.kt, ElevationTokens.kt (androidx/androidx, androidx-main)
## Side sheets
**Status**: M3 available. No "M3 Expressive update" section — no expressive-era changes. Not deprecated. **Availability is narrow: only Android Views (MDC-Android) is Available; Flutter, Jetpack Compose, and Web are all "Unavailable"** (per the overview's resources table) — consistent with there being no `SheetSideTokens.kt` in the androidx Compose Material3 token set.
### Anatomy
Standard side sheet: 1. Divider (optional), 2. Headline, 3. Container, 4. Close icon button.
Modal side sheet: 1. Back icon button (optional), 2. Headline, 3. Container, 4. Close icon button, 5. Divider (optional), 6. Action buttons (optional), 7. Scrim.
Container is the only strictly required element.
### Variants and configurations
Two variants: **standard** (coexists with primary content, doesn't block interaction — typically medium/expanded breakpoints like tablet/desktop) and **modal** (appears in front of app content, blocks other functionality until dismissed/confirmed — preferred at compact breakpoints like mobile due to limited space; can display the same content types as standard). No verbatim variant/configuration table published (specs page is organized as two prose+diagram sections with measurement tables).
### Specs (verbatim tables, source: specs page)
Standard side sheet:
| Attribute | Value |
| --- | --- |
| Start/end padding | 24dp |
| Padding between top elements | 12dp |
| Bottom actions height | 72dp |
| Bottom actions top padding | 16dp |
| Bottom actions bottom padding | 24dp |
| Bottom actions alignment (horizontal) | Left |
| Max-width | 400dp |
| Margins (when detached) | 16dp |
Modal side sheet: same as standard, plus **Start padding with icon = 16dp** (all other values identical).
Color roles (specs page): standard = Outline variant (divider), On surface variant (×2), Surface; modal = On surface variant (×2), Surface container low, On surface variant.
Additional numbers: **16dp corner radius** for modal side sheets (overview page, "Differences from M2"). Cross-check from material-components-android `SideSheet.md`: standard side sheet elevation = **0dp** (coplanar, no shadow); an example layout width of 256dp is shown in code samples (not a spec minimum/default — informational only).
### Behaviour and guidelines (Google's wording)
- Standard side sheets are supplementary surfaces mainly for **medium to expanded** breakpoints (tablet/desktop); they stay visible while the user interacts with primary content. Common uses: a list of actions affecting primary content (e.g. filters), or supplemental content/features.
- Modal side sheets are preferred at **compact** breakpoints (mobile) due to limited space; must be dismissed to interact with underlying content. Modal sheets on small screens can transition into standard sheets on larger screens.
- Side sheets have a **fixed width** and typically span the screen's height; dimensions depend on how the app's layout is subdivided. Place along a screen edge — usually the **right**, to avoid conflicting with left-edge navigation components — optionally inset by **16dp**. Don't inset it far beyond the recommended margin (makes position/scroll behavior unclear and obscures primary content).
- Back icon button: provides an exit/navigate-away affordance since primary content beside/behind the sheet stays visible. Close icon button: **highly recommended** for a consistent, accessible way to dismiss the sheet, especially when it's focused.
- Action buttons (e.g. Save/Edit/Download): use elevation, fill, and tone to call out the primary action.
- Dividers: separate action buttons from content, or user-generated from system-generated content.
- Adaptive: opening a standard side sheet shrinks the body area while keeping a trailing-edge margin. **RTL**: side sheets move to the **left** edge with all elements reversed.
- Scrolling: side sheets can scroll **vertically** independent of the rest of the UI (their scroll position persists through page scroll and vice versa); they must **never scroll horizontally** or imply horizontal scrolling (their narrow width leaves too little room to view items that way).
- Predictive back (Android): swiping left/right detaches the sheet from the top/bottom screen edges to signal closing, reveals the previous screen behind it, and scales the sheet/content in the gesture's direction.
### Accessibility
- Assistive tech must be able to **dismiss** the side sheet.
- Material **requires** a close affordance (e.g. close icon button) to always be present — without one, users can't predict the sheet's open/close flow or tell if it's transient or permanent.
- Initial focus: actions inside the sheet are reachable via **tab order** with keyboard/switch controls (example order: headline → close → cancel → save).
- Keyboard: Tab focuses a non-disabled icon button; Space or Enter activates it.
- Role: **Dialog**.
### Source URLs
- https://m3.material.io/components/side-sheets/overview (7670 bytes)
- https://m3.material.io/components/side-sheets/guidelines (12990 bytes)
- https://m3.material.io/components/side-sheets/specs (9382 bytes)
- https://m3.material.io/components/side-sheets/accessibility (7241 bytes)
- No androidx Compose Material3 token file exists for side sheets (Compose support is "Unavailable" per the site). Cross-check source: material-components-android docs, SideSheet.md.
## Menus
**Status**: M3 available; M3 Expressive update **November 2025** added **vertical menus** (new shapes, color styles, selection states, refined submenu motion, optional gaps) — recommended for new designs. Baseline menu still available. Expressive support is Android Views/Jetpack Compose-only for the "Vertical menus" name — the overview table shows "Android Views (MDC-Android): Expressive — Unavailable" and "Web: Expressive — Unavailable" (only Jetpack Compose expressive is listed Available). M2 dropdown menu and exposed dropdown menu were merged into one "menu" concept in M3 (they only differed in the triggering element).
### Anatomy
Vertical menu (11 elements): 1. Menu item, 2. Leading icon (optional), 3. Menu item text, 4. Trailing icon (optional), 5. Badge (optional), 6. Trailing text (optional), 7. Container, 8. Supporting text (optional), 9. Label text (optional), 10. Gap (optional), 11. Divider (optional).
Baseline menu (6 elements): 1. List item, 2. List item leading icon, 3. List item trailing icon, 4. Container, 5. List item trailing text, 6. Divider.
### Variants and configurations (verbatim tables, source: specs page)
| Variant | M3 | M3 Expressive |
| --- | --- | --- |
| Vertical menus | -- | Available |
| Menu (baseline) | Available | Available |
| Category | Configuration | M3 | M3 Expressive |
| --- | --- | --- | --- |
| Color | Standard | Available | Available |
| | Vibrant | -- | Available |
| Layout | Standard | Available | Available |
| | Grouped | -- | Available |
Color mappings (guidelines + specs pages): **Standard** = surface-based, lower emphasis; **Vibrant** = tertiary-based, higher emphasis — vibrant should be used sparingly since it's more prominent. Layout: **Standard** (no grouping) vs. **Grouped** (items split into clusters via a gap).
### Specs (numbers)
Baseline menu (verbatim table, specs page):
| Attribute | Value |
| --- | --- |
| Container width | 112dp min, 280dp max |
| Corner radius | 4dp |
| Vertical label text alignment | Center-aligned |
| Horizontal label text alignment | Start-aligned |
| Left/right padding | 12dp |
| Left/right padding with-icon | 12dp |
| List item height | 48dp |
| Padding between elements within a list item | 12dp |
| Divider top/bottom padding | 8dp |
| Divider height | 1dp |
| Divider width | Dynamic |
| Leading/trailing icon size | 24dp |
Cross-check, source `MenuTokens.kt` (androidx-main, baseline): `ContainerElevation` = Level2 (3dp), `ContainerShape` = ExtraSmall (4dp, matches site), `ContainerColor` = Surface container.
Baseline menu color roles (specs page): On surface variant, On surface, On surface (state layer, opacity 0.08), Surface container, On surface variant (×3), Surface container highest, Outline variant (9 roles total).
**Vertical menu (expressive) numeric measurements are not published as text anywhere on the site** — the specs page's "Measurements" section for vertical menus is diagram-only, and the corresponding androidx token files (`StandardMenuTokens.kt`, `VibrantMenuTokens.kt`) currently expose **only color tokens**, no dp/shape values (as of this M3 Expressive rollout, Nov 2025). Only the color roles are documented:
- Standard: On surface variant, On surface, On surface (state layer), Surface container low, On surface variant (×2), Tertiary container (selected), On tertiary container (selected), On surface variant (×2), On tertiary container (selected) — 11 roles.
- Vibrant: same structural roles but Tertiary-based — On tertiary container (×2), On tertiary container (state layer), Tertiary container, On tertiary container (×2), Tertiary (selected), On tertiary (selected), On tertiary container (×2), On tertiary (selected).
- `StandardMenuTokens.ContainerColor` = Surface container low; `VibrantMenuTokens.ContainerColor` = Tertiary container (confirms the standard/vibrant color mapping above).
States shown (both variants): Enabled, Disabled, Hovered, Focused, Pressed, plus **Active** (main menu revealing a submenu) for vertical menus specifically. Shape morphing: vertical-menu corners change shape as focus moves between submenus, to highlight the active submenu (exact corner values not published as text).
### Behaviour and guidelines (Google's wording)
- Use a menu for a **temporary** set of actions; use a toolbar instead if actions must stay visible at all times. A menu is more compact than an equivalent set of radio buttons or chips.
- Opens when a person selects a triggering element (icon/button/text field) or performs a trigger gesture (right-click, press-and-hold). Common uses: overflow menus, text-field dropdowns, select menus, context menus.
- Disable a menu item that's conditionally unavailable rather than removing it.
- Grouping: **gaps** are the more "expressive" way to separate item clusters (limit to one or two gaps per menu, don't vary gap size, and **never use gaps in a scrollable menu** — unsupported); **dividers** are more subtle and are the right choice for scrollable menus or text-field dropdowns where a grouped look doesn't fit; on web, use dividers to separate items.
- Slots: custom slots best suit simple content (images, progress indicators, color swatches). Slot accessibility rules: keep the menu's normal padding, keep targets ≥**48×48dp**, and **never** add buttons/switches/other direct-action controls inside a menu item slot — nested elements must perform only one action, or keyboard/screen-reader navigation breaks.
- Placement: positioned relative to a window edge, typically below/beside/in front of its trigger; if it would be cut off, it repositions to the left/right/above automatically. **Submenus** open beside (not overlapping) the parent item, and are best suited to large screens (see adaptive guidance for mobile alternatives).
- Adaptive: at **compact** breakpoints, consider swapping a menu for a **bottom sheet** (more room for items/longer labels); at **medium/expanded** breakpoints, menus work well in context and can use submenus for complex option sets.
- Motion: menus use an enter/exit transition tying them visually to their trigger; the trigger shows a pressed state while the menu is open, and selecting an item ripples. On dense/desktop products, menus can open instantly to reduce motion.
- Filtering ("autocomplete"): a menu can embed a text field that filters options as the user types; filtered items ease into their new position.
- Scrolling: a menu that can't fit all items scrolls and shows a **persistent scrollbar**; don't combine scrolling with gaps (unsupported).
- Selecting: the triggering button/icon button should stay visually unchanged (aside from adding a pressed state) after choosing a menu item — even when the menu was opened via keyboard shortcut.
- Selection modes: **Single-select** — one item selected at a time, choosing a new one auto-deselects the old; **Multi-select** — many items can be selected, and the menu stays open until the user dismisses it.
- Focus & shape morph: with multiple submenus, focus follows whichever submenu is hovered/focused; the focused submenu's corners become more rounded while others become less rounded, adding a dynamic quality to navigation.
- Density (web only): density levels shrink top/bottom padding between elements; 0 to -3 steps shown.
### Accessibility
- Assistive tech must be able to: navigate to, open, and close a menu, and navigate between/select menu items.
- Selection cues: by default, selected items change **both shape and color**; default contrast between selected/unselected items is **3:1**; it's recommended to add yet another cue on top (e.g. a checkmark) so selection isn't conveyed by color/shape alone.
- Slots: same rules as guidelines — keep standard padding, ≥48×48dp targets, never nest multiple-action controls (buttons/switches) inside an item.
- Initial focus: lands on the **first menu item** when the menu opens.
- Exiting: users expect to exit via selecting an option, **Escape** or tapping outside the menu, or the system back button; where focus lands afterward is app-dependent.
- Keyboard (verbatim table, accessibility page): **Tab** focuses the menu; **Space/Enter** opens a closed menu/submenu or selects an item in an open menu; **Up/Down arrows** open a closed menu or move focus to the next item when open; **Left/Right arrows** open/close a submenu; **Letter keys** jump focus to the next item starting with that letter; **Escape** closes the menu.
- Interactability: **disabled items can still receive focus** (just aren't selectable); **dividers and gaps can never receive focus**.
- Labeling: accessibility label = the menu item's visible text. Role is platform-dependent (verbatim table): Web = **Menu item**; Android Views = **Generic actionable element**; Jetpack Compose = **Generic actionable element**. When an item has both icon and text, the icon's own accessibility label should be marked **decorative** to avoid double-announcing.
### Source URLs
- https://m3.material.io/components/menus/overview (5554 bytes)
- https://m3.material.io/components/menus/guidelines (15868 bytes)
- https://m3.material.io/components/menus/specs (11976 bytes)
- https://m3.material.io/components/menus/accessibility (6248 bytes)
- Token files: MenuTokens.kt, StandardMenuTokens.kt, VibrantMenuTokens.kt, SegmentedMenuTokens.kt, ElevationTokens.kt, ShapeTokens.kt (androidx/androidx, androidx-main) — note StandardMenuTokens.kt/VibrantMenuTokens.kt currently expose color tokens only, no size/shape numerics.