Files
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

897 lines
52 KiB
Markdown
Raw Permalink 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 — 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**: 0360, 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 0100 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 03; levels 45 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 (05) 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, 4048dp 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 25150 (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