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
897 lines
52 KiB
Markdown
897 lines
52 KiB
Markdown
# Material Design 3 — Styles Reference (Color, Elevation, Icons, Motion, Shape, Typography)
|
||
|
||
Ground-truth extraction from m3.material.io/styles and its sub-pages, plus androidx Compose Material3
|
||
token source files where the site only renders a value inside an unrendered interactive widget.
|
||
Anything not from the live site text is explicitly marked "(not on the site; from <source>)".
|
||
|
||
---
|
||
|
||
## Color
|
||
|
||
### Principles
|
||
|
||
- Color is used to express style and communicate meaning. With dynamic color, Material puts personal
|
||
color preferences and individual needs at the forefront of systematic color application.
|
||
- The Material color system includes: a built-in set of accessible color relationships (e.g. a dark
|
||
surface color is algorithmically paired with a light text-label color so the UI automatically meets
|
||
contrast requirements); 26+ color roles mapped to components; a built-in dark theme; a static baseline
|
||
color scheme; and dynamic color (user-generated from wallpaper, or content-based from in-app content).
|
||
- Color roles are "like the numbers in a paint-by-number canvas" — the connective tissue between UI
|
||
elements and what color goes where.
|
||
- **Color roles are mapped to Material Components.** Custom components must be mapped to this same
|
||
role set.
|
||
- **Color roles ensure accessibility.** The system is built on accessible color pairings; color pairs
|
||
provide an accessible minimum 3:1 contrast.
|
||
- **Color roles are tokenized.**
|
||
- General vocabulary used in role names:
|
||
- **Surface** — backgrounds and large, low-emphasis areas.
|
||
- **Primary / Secondary / Tertiary** — accent roles used to emphasize or de-emphasize foreground elements.
|
||
- **Container** — fill color for foreground elements like buttons; not for text or icons.
|
||
- **On** — a color for text/icons *on top of* its paired parent color (e.g. "on primary" on "primary").
|
||
- **Variant** — a lower-emphasis alternative to its non-variant pair (e.g. "outline variant" vs "outline").
|
||
- The system uses a color space called **HCT** (Hue, Chroma, Tone), not HSL/RGB. HCT lets you manipulate
|
||
hue and chroma without affecting tone.
|
||
- **Hue**: 0–360, circular (perception as red/orange/yellow/…).
|
||
- **Chroma**: 0 (grey/black/white) up to roughly 120 in HCT (colorfulness); max chroma varies by hue/tone.
|
||
- **Tone**: 0 (pure black) to 100 (pure white); determines contrast. HCT tone is not interchangeable
|
||
with HSL lightness — two colors can share an HCT tone (perceived brightness) while having different
|
||
HSL lightness values.
|
||
- Dynamic color pipeline: (1) start with a source color (from wallpaper, in-app content, or hand-picked);
|
||
(2) feed it into an algorithm; (3) the algorithm generates key colors; (4) it creates a **tonal palette**
|
||
per key color (tones 0–100 in steps of 10, plus 95/98/99, some palettes have more); (5) it assigns tones
|
||
to the ~26 standard color roles for both light and dark theme; (6) the new colors are applied to the UI.
|
||
|
||
### Rules (Google's wording)
|
||
|
||
- Pair and layer color roles only as intended (e.g. primary + on primary + secondary container + on
|
||
secondary container) to keep them legible as contrast level changes. **Don't** mix roles improperly
|
||
(e.g. primary + primary container + secondary container + on surface) — this can become illegible as
|
||
contrast changes.
|
||
- **Don't** use the **outline** color for dividers (different contrast requirements) — use **outline
|
||
variant** instead.
|
||
- **Don't** use **outline** for components containing multiple elements (e.g. cards) — use **outline
|
||
variant**.
|
||
- **Don't** use **outline variant** to create visual hierarchy or define a target's visual boundary —
|
||
use **outline** or another color giving 3:1 contrast with the surface.
|
||
- **Caution**: **outline variant** can border targets like chips/buttons only if elements inside them
|
||
(icons/text) already meet 4.5:1 contrast.
|
||
- Most products won't need the **add-on** color roles (fixed/fixed-dim, on-fixed/on-fixed-variant,
|
||
surface-dim/surface-bright). "If you aren't sure whether your product should use the add-on roles, it
|
||
probably shouldn't."
|
||
- **Don't** use **fixed** colors where contrast is necessary — they don't adapt to light/dark theme and
|
||
are likely to cause contrast issues (e.g. a button fill on a permissions screen). **Do** use primary/
|
||
secondary/tertiary where contrast is needed.
|
||
- All color mappings — especially surface colors — should remain the same for a given layout region
|
||
across breakpoints (e.g. body always **surface**, navigation always **surface container**, on both
|
||
mobile and tablet).
|
||
- Error is a **static** color by default (doesn't change with dynamic color schemes) but still adapts to
|
||
light/dark theme.
|
||
- Advanced customization best practices:
|
||
- Any role starting with "on-" is guaranteed sufficient contrast with its paired role; other role pairs
|
||
may not meet the 4.5:1 (small text) / 3:1 (large text) Material contrast requirements — check before
|
||
reusing a pairing.
|
||
- Always apply **color roles**, never static hex values or raw tonal-palette values, for anything that
|
||
should respond to theme, contrast level, or dynamic color.
|
||
- Test a dynamic-color component under multiple source-color themes (light/dark; red/yellow/green/blue).
|
||
- Limit a screen to two color schemes from different source types (e.g. baseline/user-generated combined
|
||
with one content-based source) to avoid visual disarray.
|
||
- Don't replace semantic colors (e.g. red error, green success) with content-based dynamic color.
|
||
- Don't harmonize colors whose appearance should stay absolutely consistent (e.g. brand colors).
|
||
- Defining custom color roles should be considered only if the existing Material roles can't achieve the
|
||
desired result.
|
||
- Choosing a scheme: use **static (baseline)** if not ready for dynamic color, migrating from M2, building
|
||
for enterprise users, or building for iOS. Use **dynamic** if the product should personalize, react to
|
||
wallpaper/content, or offer user-controlled contrast.
|
||
|
||
### Values
|
||
|
||
#### Color roles (Compose `ColorSchemeKeyTokens`, 47 tokens; tone source `ColorLightTokens.kt` / `ColorDarkTokens.kt`)
|
||
|
||
Each role resolves to a tone from one of 5 tonal palettes (Primary, Secondary, Tertiary, Neutral,
|
||
Neutral Variant) or Error. Format: role — light theme tone — dark theme tone.
|
||
|
||
| Role | Light tone | Dark tone | Purpose (site wording) |
|
||
| --- | --- | --- | --- |
|
||
| Primary | Primary40 | Primary80 | High-emphasis fills, text, icons against surface |
|
||
| On primary | Primary100 | Primary20 | Text/icons against primary |
|
||
| Primary container | Primary90 | Primary30 | Standout fill against surface, key components like FAB |
|
||
| On primary container | Primary10 | Primary90 | Text/icons against primary container |
|
||
| Secondary | Secondary40 | Secondary80 | Less prominent fills/text/icons against surface |
|
||
| On secondary | Secondary100 | Secondary20 | Text/icons against secondary |
|
||
| Secondary container | Secondary90 | Secondary30 | Recessive fill, e.g. tonal buttons |
|
||
| On secondary container | Secondary10 | Secondary90 | Text/icons against secondary container |
|
||
| Tertiary | Tertiary40 | Tertiary80 | Complementary accent, e.g. input fields |
|
||
| On tertiary | Tertiary100 | Tertiary20 | Text/icons against tertiary |
|
||
| Tertiary container | Tertiary90 | Tertiary30 | Complementary container fill |
|
||
| On tertiary container | Tertiary10 | Tertiary90 | Text/icons against tertiary container |
|
||
| Error | Error40 | Error80 | Attention-grabbing color for urgency |
|
||
| On error | Error100 | Error20 | Text/icons against error |
|
||
| Error container | Error90 | Error30 | Attention-grabbing fill |
|
||
| On error container | Error10 | Error90 | Text/icons against error container |
|
||
| Surface | Neutral98 | Neutral6 | Default background |
|
||
| On surface | Neutral10 | Neutral90 | Text/icons on surface / surface container |
|
||
| On surface variant | NeutralVariant30 | NeutralVariant80 | Lower-emphasis text/icons on surface |
|
||
| Surface variant | NeutralVariant90 | NeutralVariant30 | (legacy; superseded by surface container roles Feb 2023) |
|
||
| Background / On background | Neutral98 / Neutral10 | Neutral6 / Neutral90 | Legacy roles, same values as surface/on surface |
|
||
| Outline | NeutralVariant50 | NeutralVariant60 | Important boundaries, e.g. text-field outline |
|
||
| Outline variant | NeutralVariant80 | NeutralVariant30 | Decorative elements, e.g. dividers |
|
||
| Inverse surface | Neutral20 | Neutral90 | Background contrasting against surrounding surface |
|
||
| Inverse on surface | Neutral95 | Neutral20 | Text/icons against inverse surface |
|
||
| Inverse primary | Primary80 | Primary40 | Actionable elements (e.g. text buttons) against inverse surface |
|
||
| Scrim | Neutral0 | Neutral0 | Scrim behind modals, at 32% opacity |
|
||
| Surface tint | (=Primary) | (=Primary) | Deprecated — use elevation level tokens instead |
|
||
|
||
Surface container family (5 levels, named by emphasis — not tied to elevation, replaced "surface +1..+5"
|
||
in Feb 2023):
|
||
|
||
| Role | Light tone | Dark tone |
|
||
| --- | --- | --- |
|
||
| Surface container lowest | Neutral100 | Neutral4 |
|
||
| Surface container low | Neutral96 | Neutral10 |
|
||
| Surface container | Neutral94 | Neutral12 |
|
||
| Surface container high | Neutral92 | Neutral17 |
|
||
| Surface container highest | Neutral90 | Neutral22 |
|
||
|
||
Bright/dim add-on surface roles (keep relative brightness across both themes, unlike default surface
|
||
which inverts):
|
||
|
||
| Role | Light tone | Dark tone |
|
||
| --- | --- | --- |
|
||
| Surface dim | Neutral87 | Neutral6 |
|
||
| Surface bright | Neutral98 | Neutral24 |
|
||
|
||
Fixed accent add-on roles (same tone in light **and** dark theme; added Feb 2023):
|
||
|
||
| Role | Tone (both themes) | Purpose |
|
||
| --- | --- | --- |
|
||
| Primary fixed | Primary90 | Fill color that stays constant across themes |
|
||
| Primary fixed dim | Primary80 | Stronger/more emphasized fixed tone |
|
||
| On primary fixed | Primary10 | Text/icons on primary fixed |
|
||
| On primary fixed variant | Primary30 | Lower-emphasis text/icons on primary fixed |
|
||
| Secondary fixed | Secondary90 | ” |
|
||
| Secondary fixed dim | Secondary80 | ” |
|
||
| On secondary fixed | Secondary10 | ” |
|
||
| On secondary fixed variant | Secondary30 | ” |
|
||
| Tertiary fixed | Tertiary90 | ” |
|
||
| Tertiary fixed dim | Tertiary80 | ” |
|
||
| On tertiary fixed | Tertiary10 | ” |
|
||
| On tertiary fixed variant | Tertiary30 | ” |
|
||
|
||
#### Baseline tonal palettes (hex; from androidx `PaletteTokens.kt`, since the site renders these only in
|
||
an interactive, non-text widget)
|
||
|
||
| Tone | Primary | Secondary | Tertiary | Neutral | Neutral Variant | Error |
|
||
| --- | --- | --- | --- | --- | --- | --- |
|
||
| 0 | #000000 | #000000 | #000000 | #000000 | #000000 | #000000 |
|
||
| 4 | — | — | — | #0F0D13 | — | — |
|
||
| 6 | — | — | — | #141218 | — | — |
|
||
| 10 | #21005D | #1D192B | #31111D | #1D1B20 | #1D1A22 | #410E0B |
|
||
| 12 | — | — | — | #211F26 | — | — |
|
||
| 17 | — | — | — | #2B2930 | — | — |
|
||
| 20 | #381E72 | #332D41 | #492532 | #322F35 | #322F37 | #601410 |
|
||
| 22 | — | — | — | #36343B | — | — |
|
||
| 24 | — | — | — | #3B383E | — | — |
|
||
| 30 | #4F378B | #4A4458 | #633B48 | #48464C | #49454F | #8C1D18 |
|
||
| 40 | #6750A4 | #625B71 | #7D5260 | #605D64 | #605D66 | #B3261E |
|
||
| 50 | #7F67BE | #7A7289 | #986977 | #79767D | #79747E | #DC362E |
|
||
| 60 | #9A82DB | #958DA5 | #B58392 | #938F96 | #938F99 | #E46962 |
|
||
| 70 | #B69DF8 | #B0A7C0 | #D29DAC | #AEA9B1 | #AEA9B4 | #EC928E |
|
||
| 80 | #D0BCFF | #CCC2DC | #EFB8C8 | #CAC5CD | #CAC4D0 | #F2B8B5 |
|
||
| 87 | — | — | — | #DED8E1 | — | — |
|
||
| 90 | #EADDFF | #E8DEF8 | #FFD8E4 | #E6E0E9 | #E7E0EC | #F9DEDC |
|
||
| 92 | — | — | — | #ECE6F0 | — | — |
|
||
| 94 | — | — | — | #F3EDF7 | — | — |
|
||
| 95 | #F6EDFF | #F6EDFF | #FFECF1 | #F5EFF7 | #F5EEFA | #FCEEEE |
|
||
| 96 | — | — | — | #F7F2FA | — | — |
|
||
| 98 | — | — | — | #FEF7FF | — | — |
|
||
| 99 | #FFFBFE | #FFFBFE | #FFFBFA | #FFFBFF | #FFFBFE | #FFFBF9 |
|
||
| 100 | #FFFFFF | #FFFFFF | #FFFFFF | #FFFFFF | #FFFFFF | #FFFFFF |
|
||
|
||
(Source: androidx Compose Material3 `PaletteTokens.kt` — the purple/violet "baseline" scheme. Any product
|
||
using a different source color will generate a different palette via the HCT algorithm, but role→tone
|
||
assignments are the same.)
|
||
|
||
#### Contrast levels
|
||
|
||
| Level | Ratio (approx.) | Notes |
|
||
| --- | --- | --- |
|
||
| Standard (default) | mixed | Emphasizes hierarchy using high- and low-contrast elements together |
|
||
| Medium | 3:1 minimum | For users needing more contrast without high-contrast side effects like halation |
|
||
| High | 7:1 | Further emphasizes essential elements (e.g. card content, not the card container) |
|
||
|
||
Contrast settings apply automatically in both light and dark theme. Custom components support contrast
|
||
levels simply by using Material color roles (e.g. primary container / on primary container) — the role's
|
||
resolved value changes per contrast level automatically.
|
||
|
||
### M3 vs M3 Expressive differences
|
||
|
||
The color pages do not explicitly label any change "M3 Expressive" the way shape/motion/typography pages
|
||
do, but the "What's new" timeline on `styles/color` lists (with the May 2025 entry coinciding with the
|
||
Expressive launch):
|
||
|
||
- **May 2025 — Three levels of contrast.** Color roles now support standard/medium/high contrast, each
|
||
tokenized (see Values above).
|
||
- **Aug 2024 — More colorful text & icons.** On-primary-container, on-secondary-container,
|
||
on-tertiary-container, on-error-container were updated in light theme to be more colorful while
|
||
remaining accessible; affects badges, buttons (all variants), chips, lists, menus, navigation bar,
|
||
navigation drawer, navigation rail, switches, toolbars.
|
||
- **Feb 2023 — Tone-based surface colors.** Replaced the old "surface +1 to +5 elevation overlay" model
|
||
with the surface/surface-container role family (not tied to elevation). Also: default light-theme
|
||
surface moved from tone 99 to tone 98; neutral palette chroma increased 4→6; dark-theme surfaces
|
||
slightly darkened (alignment with Android SysUI).
|
||
- **Feb 2023 — Additional accent colors.** Added fixed / fixed-dim roles for primary, secondary, tertiary.
|
||
|
||
### Accessibility requirements
|
||
|
||
- Color pairs provide an accessible **minimum 3:1 contrast** by design (color-role pairing system).
|
||
- Text contrast targets (also stated on `foundations/designing/color-contrast`, W3C-based):
|
||
large text (≥14pt bold / ≥18pt regular) and graphics: **≥3:1** against background; small text: **≥4.5:1**.
|
||
Disabled states do not need to meet contrast requirements.
|
||
- Non-text clustered elements (e.g. a group of buttons) should meet **3:1** contrast between container
|
||
color and background; a standalone prominent element (e.g. a FAB) does not need this because its
|
||
prominence already distinguishes it.
|
||
- High contrast mode targets **7:1**.
|
||
- Default typography color is **on surface** (or **on surface variant** as a strong alternative).
|
||
- **Color-alone rule**: hyperlinked text must use primary (or tertiary, for a less prominent link) *and*
|
||
must be underlined — color alone must not be the only signal.
|
||
|
||
### Source URLs
|
||
|
||
- https://m3.material.io/styles
|
||
- https://m3.material.io/styles/color
|
||
- https://m3.material.io/styles/color/system (identical render to /styles/color)
|
||
- https://m3.material.io/styles/color/roles
|
||
- https://m3.material.io/styles/color/system/how-the-system-works
|
||
- https://m3.material.io/styles/color/choosing-a-scheme
|
||
- https://m3.material.io/styles/color/static (= /styles/color/static/baseline)
|
||
- https://m3.material.io/styles/color/dynamic
|
||
- https://m3.material.io/styles/color/advanced
|
||
- https://m3.material.io/styles/color/advanced/apply-colors
|
||
- https://m3.material.io/styles/color/advanced/define-new-colors
|
||
- https://m3.material.io/styles/color/advanced/adjust-existing-colors
|
||
- https://m3.material.io/styles/color/resources
|
||
- https://m3.material.io/foundations/designing/color-contrast (contrast-ratio table)
|
||
- https://raw.githubusercontent.com/androidx/androidx/androidx-main/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ColorSchemeKeyTokens.kt
|
||
- .../tokens/ColorLightTokens.kt
|
||
- .../tokens/ColorDarkTokens.kt
|
||
- .../tokens/PaletteTokens.kt
|
||
|
||
---
|
||
|
||
## Elevation
|
||
|
||
### Principles
|
||
|
||
- Elevation is applied to all surfaces and components.
|
||
- Tokens codify the distance on the z-axis so components appear consistently relative to each other.
|
||
- Tokens carry no shadow or color themselves — each platform determines the specific shadow/value used
|
||
at each elevation level.
|
||
- Elevation can be shown as tonal surface colors **or** shadows.
|
||
- Avoid changing the default elevation of Material 3 components.
|
||
- Stick to using a small number of elevation levels.
|
||
- Elevation is measured as the distance between components along the z-axis in density-independent
|
||
pixels (dp).
|
||
- To successfully depict elevation, a surface must show: surface edges (contrast with surroundings),
|
||
overlap with other surfaces (at rest or in motion), and distance from other surfaces.
|
||
|
||
### Rules (do/don't)
|
||
|
||
- **Do** ensure floating elements (e.g. a FAB) have sufficient contrast with the surface beneath them.
|
||
**Don't** use colors with insufficient contrast — the relationship between surfaces must stay clear.
|
||
- By default, Material 3 surfaces use **tonal difference** to indicate separation; shadows and scrims
|
||
are alternative/additional methods.
|
||
- Any overlapping containment areas or components should use **different surface/surface-container color
|
||
roles** to communicate separation — these color roles are not tied to elevation.
|
||
- Shadow size and softness both express distance: small, sharp shadows = close proximity; larger, softer
|
||
shadows = more distance.
|
||
- "When it comes to applying shadows, less is more. The fewer levels in your UI, the more power they have
|
||
to direct attention and action."
|
||
- Use **visible shadows** to: (1) protect elements against a patterned/busy background (cards, chips,
|
||
buttons), or (2) encourage interaction (elements can temporarily lift on focus/selection/hover; a
|
||
raised element can lower when a higher element appears).
|
||
- Use a **scrim** to bring focus to elements over a large layered surface (e.g. modals, expanded
|
||
navigation menus).
|
||
|
||
### Values
|
||
|
||
#### Elevation levels (`ElevationTokens.kt`; matches the site's dp values)
|
||
|
||
| Level | dp |
|
||
| --- | --- |
|
||
| 0 | 0dp |
|
||
| 1 | 1dp |
|
||
| 2 | 3dp |
|
||
| 3 | 6dp |
|
||
| 4 | 8dp |
|
||
| 5 | 12dp |
|
||
|
||
An element's **resting state** is on levels 0–3; levels 4–5 are reserved for user-interacted states
|
||
(hover, dragged) — e.g. hovering a FAB increases elevation by 1 level (level 3 → 4), consistently across
|
||
all Material buttons.
|
||
|
||
#### Component resting elevation (from `styles/elevation/tokens`)
|
||
|
||
| Resting level | dp | Components |
|
||
| --- | --- | --- |
|
||
| 5 | 12dp | (not assigned as a resting level) |
|
||
| 4 | 8dp | (not assigned as a resting level) |
|
||
| 3 | 6dp | Date pickers, Dialogs (modal), Extended FAB, FAB, FAB menu (close button), Search, Time pickers |
|
||
| 2 | 3dp | App bar (scrolled), Menu, Navigation bar, Rich tooltip, Toolbar |
|
||
| 1 | 1dp | Banner, Bottom sheet (modal), Button (elevated), Card (elevated), Chips (elevated), Navigation drawer (modal), Side sheet (modal) |
|
||
| 0 | 0dp | App bar (not scrolled), Buttons (filled/tonal/outlined), Button groups, Cards (filled/outlined), Carousel, Chips, Dialog (full-screen), Extended FAB (in nav rail), FAB (in nav rail), FAB menu (list items), Icon buttons, List, Navigation rail, Segmented button, Side sheet (docked), Slider, Split button, Tabs |
|
||
|
||
#### Scrim
|
||
|
||
Scrims use the **scrim** color role at **32% opacity**.
|
||
|
||
### Differences from M2
|
||
|
||
- **Shadows**: instead of applying shadows by default at all levels, use shadows only when needed for
|
||
protection against a background or to encourage interaction.
|
||
- **Color**: new color mappings and compatibility with dynamic color.
|
||
- **Levels**: elevation is now described in terms of discrete levels (0–5) rather than continuous dp.
|
||
|
||
### M3 vs M3 Expressive differences
|
||
|
||
No "M3 Expressive" update is documented on the fetched elevation pages (`styles/elevation`,
|
||
`/applying-elevation`, `/tokens`) — the elevation model appears unchanged by the Expressive update.
|
||
|
||
### Accessibility requirements
|
||
|
||
- Edges (surface separation) must create sufficient contrast between surfaces — meeting or exceeding
|
||
accessible contrast ratios — to be perceived as separate. Elevation/shadow alone is treated as a visual
|
||
cue that must be reinforced with adequate color/tonal contrast, not relied on in isolation.
|
||
|
||
### Source URLs
|
||
|
||
- https://m3.material.io/styles/elevation (= /styles/elevation/overview)
|
||
- https://m3.material.io/styles/elevation/applying-elevation
|
||
- https://m3.material.io/styles/elevation/tokens
|
||
- https://raw.githubusercontent.com/androidx/androidx/androidx-main/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ElevationTokens.kt
|
||
|
||
---
|
||
|
||
## Icons
|
||
|
||
### Principles
|
||
|
||
- Icons are small symbols to easily identify actions and categories.
|
||
- Material Symbols are the new default: a variable icon font set in three styles — **outlined, rounded,
|
||
sharp** — across seven weights. (Legacy "Material Icons" remain available but lack the variable-font axes.)
|
||
- Design principles (do/don't): simplify icons for clarity/legibility, don't be overly literal or complex;
|
||
use geometric, consistent, bold shapes, don't use delicate/loose organic shapes; maintain one consistent
|
||
visual style per icon set, don't mix styles within a set.
|
||
|
||
### Rules (do/don't)
|
||
|
||
- **Don't** use the lightest weight (100) for standard-size (24dp) icons — minimum weight for that size
|
||
should be **200**. Use caution with excessive weight at 24dp too.
|
||
- **Do** apply weight consistently across a group (e.g. a navigation rail); **don't** mix different weights.
|
||
- **Do** use the same size for a Material Symbol and adjacent text; **don't** mix symbol/text sizes.
|
||
- **Do** use the same optical weight for a symbol and adjacent text; **don't** mismatch optical weights.
|
||
- **Do** shift a symbol's baseline down ~11.5% of the text size when pairing with text; **don't** use the
|
||
same baseline for symbol and text.
|
||
- **Do** position icons "on pixel" within the icon grid; **don't** place on non-integer (sub-pixel)
|
||
coordinates.
|
||
- Corners: default corner radius is **2dp**. For the **outlined** style, interior corners are square (not
|
||
rounded); for shapes ≤2dp wide, stroke corners shouldn't be rounded. **Rounded** style: both exterior
|
||
and interior corners are rounded. **Sharp** style: both exterior and interior corners reduce from 2dp
|
||
to **0dp**. **Caution**: overly round corners reduce legibility. **Don't** use inconsistent corner radii.
|
||
- Stroke: recommended stroke weight is **2dp** (regular weight, 400) with consistent weights and squared
|
||
stroke terminals; **don't** use inconsistent stroke weights or rounded stroke terminals. Complex icons
|
||
may use an optically-corrected **1.5dp** stroke to fit multiple curves in the 24×24dp space.
|
||
- **Do** make icons face forward (flat); **don't** tilt, rotate, or render icons as dimensional/isometric.
|
||
- Icon content must stay inside the **live area**; it may extend into padding toward the **trim area** if
|
||
extra visual weight is needed, but **no part may extend past the trim area**.
|
||
|
||
### Values
|
||
|
||
#### Sizes
|
||
|
||
| Size | Use |
|
||
| --- | --- |
|
||
| 20dp | Desktop, dense layouts, small-scale visuals |
|
||
| 24dp | Standard (baseline) size |
|
||
| 40dp | Larger — pairs with display/headline type, larger screens |
|
||
| 48dp | Larger — pairs with display/headline type, larger screens |
|
||
|
||
#### Layout (24dp standard icon)
|
||
|
||
| Region | Size |
|
||
| --- | --- |
|
||
| Trim area (total canvas) | 24dp × 24dp |
|
||
| Live area | 20dp × 20dp |
|
||
| Padding (live→trim) | 2dp around the perimeter |
|
||
|
||
#### Grid and keyline shapes (within the 24dp grid)
|
||
|
||
| Keyline | Dimensions |
|
||
| --- | --- |
|
||
| Square | 18dp × 18dp |
|
||
| Circle | 20dp diameter |
|
||
| Vertical rectangle | 20dp height × 16dp width |
|
||
| Horizontal rectangle | 16dp height × 20dp width |
|
||
|
||
#### Corner radius by style
|
||
|
||
| Style | Exterior corner | Interior corner |
|
||
| --- | --- | --- |
|
||
| Outlined | 2dp rounded | Square (not rounded) |
|
||
| Rounded | 2dp rounded | Rounded |
|
||
| Sharp | 0dp | 0dp |
|
||
|
||
#### Material Symbols variable-font axes
|
||
|
||
| Axis | Range | Notes |
|
||
| --- | --- | --- |
|
||
| Weight | 100 (thin) – 700 (bold) | Also affects overall symbol size; min 200 recommended at 24dp |
|
||
| Fill | 0 – 1 | 0 = unfilled/outlined, 1 = fully filled; communicates state transitions |
|
||
| Grade | negative / 0 / positive (site examples: −25, 0) | Finer-grained than weight; doesn't change width or line breaks. Default grade is 0 for a dark icon on light background, **−25** for a light icon on dark background (compensates for visual bleed/halation). Positive grade for emphasis (e.g. active state). |
|
||
| Optical size | 20dp – 48dp | Auto-adjusts stroke weight so the icon "looks the same" as size scales; use 20dp for dense desktop layouts, 40–48dp to highlight primary actions |
|
||
|
||
#### Icon styles (3): Outlined, Rounded, Sharp — see corner-radius table above.
|
||
|
||
### M3 vs M3 Expressive differences
|
||
|
||
No "M3 Expressive" update is documented on the fetched icon pages (`styles/icons`,
|
||
`/designing-icons`, `/applying-icons`). Material Symbols (three styles + four variable axes) predate the
|
||
Expressive update; no Expressive-specific icon changes were found on the site.
|
||
|
||
### Accessibility requirements
|
||
|
||
- Icon meaning must always be unambiguous and accessible; use caution displaying icons without labels.
|
||
Label text (short, meaningful) should be used especially for navigation.
|
||
- Below **20dp**, symbols that are complex/highly-detailed, have multiple parts, or represent a key
|
||
action essential to the product should have an accompanying text label. Simple symbols (e.g. a star for
|
||
ratings) can be used alone at any size if they remain identifiable.
|
||
- **Target size**: a 24dp symbol should have a default **target size of 48dp**.
|
||
|
||
### Source URLs
|
||
|
||
- https://m3.material.io/styles/icons (= /styles/icons/overview)
|
||
- https://m3.material.io/styles/icons/designing-icons
|
||
- https://m3.material.io/styles/icons/applying-icons
|
||
|
||
---
|
||
|
||
## Motion
|
||
|
||
### Principles
|
||
|
||
- May 2025: Material introduced the **motion physics system** with M3 Expressive — a spring-based system
|
||
replacing the previous easing-and-duration system, intended to feel "more alive, fluid, and natural,"
|
||
and to be easier to implement/customize.
|
||
- Two preset **motion schemes**: **Expressive** (Material's opinionated default; overshoots final values
|
||
to add bounce; use for most situations, hero moments, key interactions) and **Standard** (minimal
|
||
bounce, eases into final values; for utilitarian products). Custom schemes can also be created.
|
||
- A **spring** is defined by three attributes: **stiffness** (hardness — higher = faster resolve),
|
||
**damping** (how fast bounce wears out — higher = faster stop; damping = 1 removes bounce entirely),
|
||
and **initial velocity** (starting speed, combines with stiffness/damping to affect total duration).
|
||
- Springs are versatile (one spring can drive transitions, button effects, gestures — consistent feel)
|
||
and feel natural/predictable, handling gesture interruption and retargeting seamlessly.
|
||
- Two spring **styles**: **Spatial** (movement — x/y position, rotation, size, rounded corners; overshoots
|
||
and bounces into place) and **Effects** (color, opacity; no overshoot).
|
||
- Three **speeds** per style: **default**, **fast**, **slow**. Most motion uses default; smaller elements
|
||
may use fast; larger elements may use slow. The exact values differ by device class (wearable/phone/
|
||
tablet) even though the *relative* speed ordering (fast < default < slow) is constant.
|
||
- Token naming: e.g. `md.sys.motion.spring.fast.spatial` — the scheme (expressive/standard) is applied at
|
||
the product level, not baked into the token name, so schemes can be swapped without re-tokenizing.
|
||
- On Jetpack Compose, **21 Material components** use the motion physics system by default (Android Views/
|
||
MDC-Android: available but not yet wired into components; Web: compatible via curve approximations).
|
||
- Legacy **easing and duration** tokens remain available as a fallback and are still used for transition
|
||
animation on platforms/paths not yet migrated to springs.
|
||
|
||
### Rules (do/don't; easing & duration choice)
|
||
|
||
- Choose the **Emphasized** easing set for most transitions (captures the M3 style); use **Standard**
|
||
only for small, utility-focused, quick transitions, and as the fallback on platforms without Emphasized
|
||
support (iOS, Web).
|
||
- Easing by transition type:
|
||
- **Begin and end on screen** → **Emphasized** (speeds up quickly, gentle rest, emphasizes the end).
|
||
- **Enter the screen** → **Emphasized decelerate** (starts at peak velocity, gentle rest).
|
||
- **Exit the screen permanently** → **Emphasized accelerate** (starts at rest, ends at peak velocity —
|
||
implies it can't be retrieved).
|
||
- **Exit the screen temporarily** → **Emphasized** (ends at rest just off-screen — implies it can be
|
||
retrieved, e.g. a drawer).
|
||
- Duration by transition size: small-area transitions get short durations; large-area transitions get
|
||
long durations (consistent sense of speed).
|
||
- Duration by direction: **exit/dismiss/collapse** → shorter durations (less attention needed); **enter/
|
||
persist** → longer durations (focus attention on what's new).
|
||
- Suggested easing+duration pairs (defaults good for most transitions):
|
||
|
||
| Easing | Duration | Transition type |
|
||
| --- | --- | --- |
|
||
| Emphasized | 500ms | Begin and end on screen |
|
||
| Emphasized decelerate | 400ms | Enter the screen |
|
||
| Emphasized accelerate | 200ms | Exit the screen |
|
||
| Standard | 300ms | Begin and end on screen |
|
||
| Standard decelerate | 250ms | Enter the screen |
|
||
| Standard accelerate | 200ms | Exit the screen |
|
||
|
||
- Motion customization levels: **Level 1** — use a default scheme (expressive/standard) as-is; **Level 2**
|
||
— create a custom `MotionScheme` (custom `AnimationSpec` per property) applied product-wide; **Level 3**
|
||
— swap the scheme per element/screen (override the `CompositionLocal`) while most of the product uses
|
||
the primary scheme.
|
||
- Transition patterns documented: container transform (full-screen and within-screen), forward/backward,
|
||
lateral, top-level, enter/exit (within screen bounds and beyond screen bounds), skeleton loaders.
|
||
|
||
### Values
|
||
|
||
#### Expressive motion scheme — spring tokens (`ExpressiveMotionTokens.kt`)
|
||
|
||
| Speed | Style | Damping | Stiffness |
|
||
| --- | --- | --- | --- |
|
||
| Fast | Spatial | 0.6 | 800.0 |
|
||
| Fast | Effects | 1.0 | 3800.0 |
|
||
| Default | Spatial | 0.8 | 380.0 |
|
||
| Default | Effects | 1.0 | 1600.0 |
|
||
| Slow | Spatial | 0.8 | 200.0 |
|
||
| Slow | Effects | 1.0 | 800.0 |
|
||
|
||
#### Standard motion scheme — spring tokens (`StandardMotionTokens.kt`)
|
||
|
||
| Speed | Style | Damping | Stiffness |
|
||
| --- | --- | --- | --- |
|
||
| Fast | Spatial | 0.9 | 1400.0 |
|
||
| Fast | Effects | 1.0 | 3800.0 |
|
||
| Default | Spatial | 0.9 | 700.0 |
|
||
| Default | Effects | 1.0 | 1600.0 |
|
||
| Slow | Spatial | 0.9 | 300.0 |
|
||
| Slow | Effects | 1.0 | 800.0 |
|
||
|
||
#### Web curve equivalents for springs (from `styles/motion/overview/specs`; springs aren't natively
|
||
supported on the web, so Web should use these approximated cubic-bezier curves with matching duration)
|
||
|
||
| Spring | Cubic-bezier | Duration |
|
||
| --- | --- | --- |
|
||
| Expressive fast spatial | 0.42, 1.67, 0.21, 0.90 | 350ms |
|
||
| Expressive default spatial | 0.38, 1.21, 0.22, 1.00 | 500ms |
|
||
| Expressive slow spatial | 0.39, 1.29, 0.35, 0.98 | 650ms |
|
||
| Expressive fast effects | 0.31, 0.94, 0.34, 1.00 | 150ms |
|
||
| Expressive default effects | 0.34, 0.80, 0.34, 1.00 | 200ms |
|
||
| Expressive slow effects | 0.34, 0.88, 0.34, 1.00 | 300ms |
|
||
| Standard fast spatial | 0.27, 1.06, 0.18, 1.00 | 350ms |
|
||
| Standard default spatial | 0.27, 1.06, 0.18, 1.00 | 500ms |
|
||
| Standard slow spatial | 0.27, 1.06, 0.18, 1.00 | 750ms |
|
||
| Standard fast effects | 0.31, 0.94, 0.34, 1.00 | 150ms |
|
||
| Standard default effects | 0.34, 0.80, 0.34, 1.00 | 200ms |
|
||
| Standard slow effects | 0.34, 0.88, 0.34, 1.00 | 300ms |
|
||
|
||
#### Legacy easing tokens (`styles/motion/easing-and-duration/tokens-specs`; curves confirmed in
|
||
androidx `MotionTokens.kt`, noted where Compose's single-cubic-bezier approximation differs from the
|
||
platform-accurate multi-segment Android `PathInterpolator`)
|
||
|
||
| Token | Android | CSS | Flutter | iOS |
|
||
| --- | --- | --- | --- | --- |
|
||
| `md.sys.motion.easing.emphasized` | PathInterpolator(M 0,0 C 0.05,0 0.133333,0.06 0.166666,0.4 C 0.208333,0.82 0.25,1 1,1) | N/A (use Standard) | `easeInOutCubicEmphasized` | N/A (use Standard) |
|
||
| `md.sys.motion.easing.emphasized.decelerate` | PathInterpolator(0.05, 0.7, 0.1, 1) | cubic-bezier(0.05,0.7,0.1,1.0) | Cubic(0.05,0.7,0.1,1.0) | ControlPoints 0.05,0.7,0.1,1.0 |
|
||
| `md.sys.motion.easing.emphasized.accelerate` | PathInterpolator(0.3, 0, 0.8, 0.15) | cubic-bezier(0.3,0.0,0.8,0.15) | Cubic(0.3,0.0,0.8,0.15) | ControlPoints 0.3,0.0,0.8,0.15 |
|
||
| `md.sys.motion.easing.standard` | PathInterpolator(0.2, 0, 0, 1) | cubic-bezier(0.2,0.0,0,1.0) | Cubic(0.2,0.0,0,1.0) | ControlPoints 0.2,0.0,0.0,1.0 |
|
||
| `md.sys.motion.easing.standard.decelerate` | PathInterpolator(0, 0, 0, 1) | cubic-bezier(0,0,0,1) | Cubic(0,0,0,1) | ControlPoints 0.0,0.0,0.0,1.0 |
|
||
| `md.sys.motion.easing.standard.accelerate` | PathInterpolator(0.3, 0, 1, 1) | cubic-bezier(0.3,0,1,1) | Cubic(0.3,0,1,1) | ControlPoints 0.3,0.0,1.0,1.0 |
|
||
|
||
Compose `MotionTokens.kt` also defines `EasingLegacyCubicBezier` = CubicBezierEasing(0.4, 0.0, 0.2, 1.0)
|
||
(M2-era "standard" curve) and `EasingLinearCubicBezier` = (0,0,1,1) — not shown on the site pages fetched
|
||
(not on the site; from androidx `MotionTokens.kt`).
|
||
|
||
#### Legacy duration tokens (site table; matches androidx `MotionTokens.kt` exactly)
|
||
|
||
| Token | Value |
|
||
| --- | --- |
|
||
| `md.sys.motion.duration.short1` | 50ms |
|
||
| `md.sys.motion.duration.short2` | 100ms |
|
||
| `md.sys.motion.duration.short3` | 150ms |
|
||
| `md.sys.motion.duration.short4` | 200ms |
|
||
| `md.sys.motion.duration.medium1` | 250ms |
|
||
| `md.sys.motion.duration.medium2` | 300ms |
|
||
| `md.sys.motion.duration.medium3` | 350ms |
|
||
| `md.sys.motion.duration.medium4` | 400ms |
|
||
| `md.sys.motion.duration.long1` | 450ms |
|
||
| `md.sys.motion.duration.long2` | 500ms |
|
||
| `md.sys.motion.duration.long3` | 550ms |
|
||
| `md.sys.motion.duration.long4` | 600ms |
|
||
| `md.sys.motion.duration.extra-long1` | 700ms |
|
||
| `md.sys.motion.duration.extra-long2` | 800ms |
|
||
| `md.sys.motion.duration.extra-long3` | 900ms |
|
||
| `md.sys.motion.duration.extra-long4` | 1000ms |
|
||
|
||
### M3 vs M3 Expressive differences
|
||
|
||
- **Physics-based motion system** (springs: stiffness/damping/initial velocity) replaces the
|
||
easing-and-duration system as the primary motion model. Legacy easing/duration tokens remain as a
|
||
fallback and still drive some transitions.
|
||
- Two schemes, **Expressive** and **Standard**, selectable/customizable at up to 3 levels of depth
|
||
(default scheme → custom scheme → per-element scheme override).
|
||
- Spring tokens split into **spatial** vs **effects**, each with **fast/default/slow** — a 2×3 matrix per
|
||
scheme (12 values total across both schemes).
|
||
- 21 Jetpack Compose components use the physics system by default; component motion is largely driven by
|
||
just two tokens in practice: **expressive fast spatial** and **expressive fast effects**.
|
||
- Shape morph (see Shape section) uses the **expressive** motion scheme by default.
|
||
|
||
### Accessibility requirements
|
||
|
||
- No general "prefers-reduced-motion" policy was found stated on `styles/motion` itself. Reduced-motion
|
||
handling is documented per component instead — e.g. `components/carousel/accessibility`: "When reduced
|
||
motion settings are turned on, the parallax effect should be removed and carousel items should no
|
||
longer expand as they come into view. All items are the same size," and hero carousels should keep the
|
||
small item only partially visible rather than animating it. (Component-level source, included here
|
||
because it is the only "reduced motion" guidance found in the crawl.)
|
||
- `components/menus/guidelines`: "In dense products, such as on desktop, menus can open instantly to
|
||
reduce motion."
|
||
|
||
### Source URLs
|
||
|
||
- https://m3.material.io/styles/motion (= /styles/motion/overview = /styles/motion/overview/how-it-works)
|
||
- https://m3.material.io/styles/motion/overview/specs
|
||
- https://m3.material.io/styles/motion/easing-and-duration
|
||
- https://m3.material.io/styles/motion/easing-and-duration/tokens-specs
|
||
- https://m3.material.io/styles/motion/transitions
|
||
- https://m3.material.io/components/carousel/accessibility (reduced motion example)
|
||
- https://m3.material.io/components/menus/guidelines (reduced motion example)
|
||
- https://raw.githubusercontent.com/androidx/androidx/androidx-main/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/MotionTokens.kt
|
||
- .../tokens/ExpressiveMotionTokens.kt
|
||
- .../tokens/StandardMotionTokens.kt
|
||
|
||
---
|
||
|
||
## Shape
|
||
|
||
### Principles
|
||
|
||
- The M3 shape system includes original shapes, a corner radius scale, and built-in shape morphing.
|
||
- Use abstract shapes thoughtfully to add emphasis and decorative flair; leverage Material shapes for
|
||
built-in shape morphing.
|
||
- Rectangular shapes are fully rounded in all corners by default; individual corners can be adjusted to
|
||
create asymmetrical shapes.
|
||
- Use shape and type "in harmony" — M3 shapes are designed to echo key visual attributes of M3 typography
|
||
(e.g. M3 shapes and Google Sans Flex share roundness attributes).
|
||
- Shape morph should respond to user interaction and connect function and feeling — use it to communicate
|
||
interaction states (e.g. a selected button), actions in progress (e.g. typing, loading), or environment
|
||
changes (sound, temperature, time of day).
|
||
- "Be bold and dare to embrace tension" — contrast (square + rounded, unconventional shapes) creates more
|
||
dynamic, memorable, expressive design; Material historically favored rounded shapes only.
|
||
- Shape is **versatile, not semantic** — avoid making a shape literal or assigning it one fixed meaning
|
||
(e.g. a wavy loading indicator isn't a literal progress waveform and could be reused elsewhere).
|
||
- Use abstract shapes sparingly — don't compromise clarity for visual design; be intentional and consider
|
||
how a shape fits the product narrative.
|
||
- Emphasize aesthetic moments (imagery, avatar masking) with shape — these are the most flexible,
|
||
creative uses.
|
||
- Shape (with motion) can create a 2.5D illusion of depth on flat visuals.
|
||
|
||
### Rules (do/don't)
|
||
|
||
- Components can have symmetric (all corners equal) or asymmetric ("inner corner") shapes; both use the
|
||
same 10-step scale. Asymmetric/inner corners are used in components with closely-grouped items (menus,
|
||
split buttons) — inner-corner component tokens always map to individual corner-shape tokens.
|
||
- Customization happens at **style** level (changing what a named style like "medium" resolves to —
|
||
affects every component mapped to it, unless overridden) or **component** level (remapping one
|
||
component to a different named style, e.g. remapping a button's default "full" to "small"/"medium").
|
||
- The shape style family can be customized from **rounded** to **cut** (straight line instead of curve);
|
||
add extra padding to avoid clipping content, especially in information-dense components. **Caution**:
|
||
don't apply large/full corners to information-dense components (e.g. cards).
|
||
- **Optical roundness**: when nesting rounded objects, don't reuse the same radius for both. Formula:
|
||
**outer radius − padding = inner radius** (example given: 48dp − 14dp = 34dp). **Do** use different,
|
||
proportional radii for nested components; **don't** use the same radius as the container.
|
||
- Use the shape library for mostly visual/decorative elements; avoid unconventional shapes on text-heavy
|
||
containers; use shapes sparingly for emphasis and delight.
|
||
|
||
### Values
|
||
|
||
#### Corner radius scale (10 styles; matches androidx `ShapeTokens.kt` exactly)
|
||
|
||
| # | Style | Value |
|
||
| --- | --- | --- |
|
||
| 1 | None | 0dp |
|
||
| 2 | Extra small | 4dp |
|
||
| 3 | Small | 8dp |
|
||
| 4 | Medium | 12dp |
|
||
| 5 | Large | 16dp |
|
||
| 6 | Large increased | 20dp |
|
||
| 7 | Extra large | 28dp |
|
||
| 8 | Extra large increased | 32dp |
|
||
| 9 | Extra extra large | 48dp |
|
||
| 10 | Full | fully rounded (Compose: `CircleShape`, not a fixed dp value) |
|
||
|
||
(M2 used a 3-level shape scale based on component-container size; M3 uses this 10-level scale based on
|
||
corner roundedness instead.)
|
||
|
||
#### Shape library
|
||
|
||
35 pre-made shapes in the Material shape library (Figma Design Kit / Jetpack Compose `MaterialShapes`
|
||
API), designed to morph seamlessly into one another. Used by the standard **button group** and
|
||
**loading indicator** components by default.
|
||
|
||
### M3 vs M3 Expressive differences (May 2025 "M3 Expressive update")
|
||
|
||
- Added **35 new shapes** and **shape morphing** to the Material Shape Library (Figma) and Jetpack
|
||
Compose (`MaterialShapes` API).
|
||
- Added new shape principles and a refreshed art direction.
|
||
- Added corner-radius tokens: **Large increased (20dp)**, **Extra large increased (32dp)**,
|
||
**Extra extra large (48dp)** — these three styles are new to the 10-step scale.
|
||
- Updated "fully rounded" corners to use the dedicated **Full** style; previously this was defined as
|
||
50% of the component's size.
|
||
- Shape morphing uses the **expressive** motion scheme by default (see Motion section); can be switched
|
||
to the standard scheme. Access is via a platform API — Android: Compose `MaterialShapes`; Web: not
|
||
currently available.
|
||
|
||
### Accessibility requirements
|
||
|
||
No shape-specific accessibility requirements (contrast ratios, color-alone rule, reduced motion) were
|
||
found on the fetched shape pages. The only adjacent accessibility-flavored guidance is the "optical
|
||
roundness" and "cut corners need extra padding" rules above, which are about legibility/clipping rather
|
||
than a formal accessibility requirement.
|
||
|
||
### Source URLs
|
||
|
||
- https://m3.material.io/styles/shape (= /styles/shape/overview-principles)
|
||
- https://m3.material.io/styles/shape/corner-radius-scale
|
||
- https://m3.material.io/styles/shape/shape-morph
|
||
- https://raw.githubusercontent.com/androidx/androidx/androidx-main/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ShapeTokens.kt
|
||
|
||
---
|
||
|
||
## Typography
|
||
|
||
### Principles
|
||
|
||
- Use typography to make content readable and beautiful.
|
||
- M3 has **one type scale** containing two sets of type styles: **15 baseline** and **15 emphasized**
|
||
(added in the Expressive update) — 30 styles total, both sets following the same scale from Display
|
||
Large to Label Small.
|
||
- Five style **roles**: **Display, Headline, Title, Body, Label** — each with Large/Medium/Small (Display/
|
||
Headline/Title/Body) — see the type-scale table below for exact members.
|
||
- **Display**: largest text on screen; short, important text/numerals; best on large screens; can use
|
||
a more expressive/handwritten/script font; set optical size appropriately.
|
||
- **Headline**: short, high-emphasis text on smaller screens; can use expressive typefaces if line
|
||
height/letter spacing are adjusted to preserve readability.
|
||
- **Title**: medium-emphasis, relatively short text (e.g. dividing secondary content); use caution with
|
||
expressive/display/handwritten/script fonts here.
|
||
- **Body**: longer passages; use typefaces meant for body copy, readable at small size; avoid
|
||
expressive/decorative fonts.
|
||
- **Label**: small, utilitarian text inside components (e.g. buttons use Label Large) or captions.
|
||
- Two typeface roles: **Brand** (larger styles — Display/Headline — focused on expression) and **Plain**
|
||
(smaller styles — Body/Label — focused on readability). Roboto is the default for both.
|
||
- Typesetting: use **padding + bounding box** method for Web/iOS (line height = bounding box height, text
|
||
vertically centered — CSS "half-leading"); use the **baseline** method for Android/platform-agnostic
|
||
specs (distances measured to the invisible baseline a line of text rests on).
|
||
- **Line height**: recommend a **1.2×** ratio of type size for larger styles (title/headline/display);
|
||
recommend **~1.5×** for smaller styles (body/label) — too tight undermines flow, too loose feels
|
||
incohesive.
|
||
- Use **tabular (monospaced) numbers**, not proportional digits, wherever values change often (tables,
|
||
clocks) to prevent layout shift and aid scanning.
|
||
- Language script height: line height can auto-adapt by script category so components (with vertical
|
||
padding) don't clip. Categories: **Small/base** (~Latin, Cyrillic, Greek, Hebrew, except Vietnamese);
|
||
**Medium** (~7% taller: Arabic, Chinese, Hindi, Japanese, Korean, Vietnamese, most others); **Large**
|
||
(~30% taller: Burmese, Telugu); **Extra large** (~100% taller: Nastaliq). Default to Medium since most
|
||
languages fall there; components with a fixed height are built for Small and may not auto-adapt.
|
||
- Material's default type scale follows the **Major Second (1.125)** modular scale, anchored to 14 (the
|
||
base size for body text).
|
||
|
||
### Rules (do/don't)
|
||
|
||
- Emphasized styles are **not** used by default by Material components — swap the baseline token for the
|
||
matching emphasized token (e.g. `md.sys.typescale.display-large` → `md.sys.typescale.emphasized.
|
||
display-large`) deliberately.
|
||
- Recommended emphasized-style use: badges, buttons (primary actions), extended FAB, selected list items,
|
||
selected menu items, and generally selection/actions/headlines/other editorial-treatment moments —
|
||
not just for decoration.
|
||
- Emphasized can be combined with **weight** (apply to already-bold text) and **context** (apply
|
||
selectively to selected/unread/key-interaction states) simultaneously.
|
||
- When customizing the scale: change brand/plain typeface tokens if swapping fonts; adjust line height
|
||
and letter spacing to refine appearance; **avoid changing type size** (can break component
|
||
layout/reflow); keep both baseline and emphasized styles visually consistent (e.g. all wider than
|
||
baseline, not just some).
|
||
- Customizing the M3 type scale or individual styles may forgo future Material typography token updates.
|
||
- Hyperlinks: use **primary** (or **tertiary** for a less prominent link) and the text must be
|
||
**underlined** — never color alone.
|
||
- **Do** use the same size and same optical weight for Material Symbols paired with text; **don't** mix.
|
||
|
||
### Values
|
||
|
||
#### Type scale — baseline set (`TypeScaleTokens.kt`)
|
||
|
||
| Style | Size | Line height | Tracking | Weight | Family |
|
||
| --- | --- | --- | --- | --- | --- |
|
||
| Display Large | 57sp | 64sp | −0.2sp | Regular | Brand |
|
||
| Display Medium | 45sp | 52sp | 0sp | Regular | Brand |
|
||
| Display Small | 36sp | 44sp | 0sp | Regular | Brand |
|
||
| Headline Large | 32sp | 40sp | 0sp | Regular | Brand |
|
||
| Headline Medium | 28sp | 36sp | 0sp | Regular | Brand |
|
||
| Headline Small | 24sp | 32sp | 0sp | Regular | Brand |
|
||
| Title Large | 22sp | 28sp | 0sp | Regular | Brand |
|
||
| Title Medium | 16sp | 24sp | 0.2sp | Medium | Plain |
|
||
| Title Small | 14sp | 20sp | 0.1sp | Medium | Plain |
|
||
| Body Large | 16sp | 24sp | 0.5sp | Regular | Plain |
|
||
| Body Medium | 14sp | 20sp | 0.2sp | Regular | Plain |
|
||
| Body Small | 12sp | 16sp | 0.4sp | Regular | Plain |
|
||
| Label Large | 14sp | 20sp | 0.1sp | Medium | Plain |
|
||
| Label Medium | 12sp | 16sp | 0.5sp | Medium | Plain |
|
||
| Label Small | 11sp | 16sp | 0.5sp | Medium | Plain |
|
||
|
||
#### Type scale — emphasized set (Expressive; same size/line-height/family as baseline, heavier weight
|
||
and slightly different tracking on some styles)
|
||
|
||
| Style | Size | Line height | Tracking | Weight | Family |
|
||
| --- | --- | --- | --- | --- | --- |
|
||
| Display Large Emphasized | 57sp | 64sp | 0sp | Medium | Brand |
|
||
| Display Medium Emphasized | 45sp | 52sp | 0sp | Medium | Brand |
|
||
| Display Small Emphasized | 36sp | 44sp | 0sp | Medium | Brand |
|
||
| Headline Large Emphasized | 32sp | 40sp | 0sp | Medium | Brand |
|
||
| Headline Medium Emphasized | 28sp | 36sp | 0sp | Medium | Brand |
|
||
| Headline Small Emphasized | 24sp | 32sp | 0sp | Medium | Brand |
|
||
| Title Large Emphasized | 22sp | 28sp | 0sp | Medium | Brand |
|
||
| Title Medium Emphasized | 16sp | 24sp | 0.15sp | Bold | Plain |
|
||
| Title Small Emphasized | 14sp | 20sp | 0.1sp | Bold | Plain |
|
||
| Body Large Emphasized | 16sp | 24sp | 0.15sp | Medium | Plain |
|
||
| Body Medium Emphasized | 14sp | 20sp | 0.25sp | Medium | Plain |
|
||
| Body Small Emphasized | 12sp | 16sp | 0.4sp | Medium | Plain |
|
||
| Label Large Emphasized | 14sp | 20sp | 0.1sp | Bold | Plain |
|
||
| Label Medium Emphasized | 12sp | 16sp | 0.5sp | Bold | Plain |
|
||
| Label Small Emphasized | 11sp | 16sp | 0.5sp | Bold | Plain |
|
||
|
||
(Size, line height and font family are unchanged between a baseline style and its emphasized counterpart;
|
||
weight steps up — Regular→Medium or Medium→Bold — and a few styles gain slightly wider tracking. Source:
|
||
`TypeScaleTokens.kt`; the site's `styles/typography/type-scale-tokens` page describes these sets in prose
|
||
and confirms "30 styles: 15 baseline, 15 emphasized" and the naming convention, but renders the actual
|
||
numeric table only inside an interactive, non-text widget.)
|
||
|
||
`TypefaceTokens.kt` weight mapping used above: Regular = `FontWeight.Normal`, Medium = `FontWeight.
|
||
Medium`, Bold = `FontWeight.Bold`; Brand/Plain both default to the platform sans-serif (Compose fallback;
|
||
the actual M3 web/design spec default typeface is **Roboto** for both Brand and Plain, per
|
||
`styles/typography/fonts`).
|
||
|
||
#### Fonts
|
||
|
||
| Font | Role | Notes |
|
||
| --- | --- | --- |
|
||
| Roboto | Default (Brand + Plain) | Static; used in the M3 type scale by default; 3,300+ glyphs |
|
||
| Roboto Flex | Variable, not yet part of the type scale | Axes: Slant, Width, Weight, Grade, Optical Size, plus advanced axes (thick stroke XOPQ, thin stroke YOPQ, counter width XTRA, uppercase height YTUC, lowercase height YTLC, ascender height YTAS, descender depth YTDE, figure height YTFI); width range 25–150 (example) |
|
||
| Roboto Serif | Variable | Reading-focused; wide weight/width range |
|
||
| Roboto Mono | Variable | Axes: Weight, Italic; monospaced, good for code/tabular numbers |
|
||
| Noto Sans | Fallback | Axes: Width, Weight, Italic; 150+ scripts, used when a language is unsupported |
|
||
|
||
Font fallback order (e.g. for Roboto Flex): **Roboto Flex → Roboto → Noto Sans**.
|
||
|
||
#### Units
|
||
|
||
| Platform | Font size unit | Conversion | Letter spacing unit | Conversion |
|
||
| --- | --- | --- | --- | --- |
|
||
| Android | sp | 1.0 (base) | em | tracking(px) / font size(sp) |
|
||
| Web | rem | sp / 16 = rem (16px root default) | rem | tracking(px) / font size(sp) |
|
||
|
||
Example: 16sp = 1rem; 24sp = 1.5rem; 60sp = 3.75rem. 0.2 tracking / 16sp = 0.0125 em (or rem on web).
|
||
|
||
### M3 vs M3 Expressive differences (May 2025 "M3 Expressive update")
|
||
|
||
- Added **15 emphasized type styles** alongside the existing 15 baseline styles — 30 total. Emphasized
|
||
styles have higher weight (and minor tracking adjustments) and are meant for bold/selection/emphasis
|
||
moments; baseline and emphasized are meant to be used together, not as a full replacement.
|
||
- New **emphasized token namespace**: `md.sys.typescale.emphasized.<style>` alongside
|
||
`md.sys.typescale.<style>`.
|
||
- (Aug 2026, post-Expressive) **Language script height support**: line height can automatically adapt by
|
||
language script category (small/medium/large/extra large) — see Principles above.
|
||
- Roboto Flex / variable-font axis guidance (weight, grade, width, optical size — "editorial treatments")
|
||
is presented as an Expressive-era authoring technique, though Roboto Flex itself is "not yet part of
|
||
the M3 type scale."
|
||
|
||
### Accessibility requirements
|
||
|
||
- Text contrast: **≥3:1** for large text (≥14pt bold / ≥18pt regular) and graphics; **≥4.5:1** for small
|
||
text (restated from `foundations/designing/color-contrast`).
|
||
- Default typography color is **on surface** (or **on surface variant**).
|
||
- **Color-alone rule**: hyperlinked text must be **underlined**, in addition to using primary/tertiary color.
|
||
- Avoid very light/thin weights for body text — low-resolution displays can struggle to render thin type,
|
||
especially at small sizes; reserve very light weights for larger sizes such as display type.
|
||
- Avoid excessive weight/bold at small label sizes — it can reduce readability (navigation-bar example).
|
||
- Tabular numbers should be used where digits change frequently, to avoid disorienting layout shifts.
|
||
|
||
### Source URLs
|
||
|
||
- https://m3.material.io/styles/typography (= /styles/typography/overview)
|
||
- https://m3.material.io/styles/typography/type-scale-tokens
|
||
- https://m3.material.io/styles/typography/fonts
|
||
- https://m3.material.io/styles/typography/applying-type
|
||
- https://m3.material.io/styles/typography/editorial-treatments
|
||
- https://raw.githubusercontent.com/androidx/androidx/androidx-main/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/TypeScaleTokens.kt
|
||
- .../tokens/TypefaceTokens.kt
|