DESIGN
This is a community-generated DESIGN.md derived from Material Design 3's public documentation. It is not an official document published by the Material Design team. Token values reflect the M3 baseline scheme (seed:
#6750A4). For production use, generate your own scheme from your brand seed using the Material Theme Builder ormaterial-color-utilities.
name: Material Design 3 — Baseline description: > Google's Material Design 3 design system. Expressive, accessible, adaptive. Built on a three-tier token architecture with Dynamic Color, tonal surface elevation, and a named shape scale. M3 Expressive (May 2025) adds 35 abstract shapes, shape morphing, and 15 new emphasized typescale styles.
colors: light: primary: "#6750A4" on-primary: "#FFFFFF" primary-container: "#EADDFF" on-primary-container: "#21005D" inverse-primary: "#D0BCFF" secondary: "#625B71" on-secondary: "#FFFFFF" secondary-container: "#E8DEF8" on-secondary-container: "#1D192B" tertiary: "#7D5260" on-tertiary: "#FFFFFF" tertiary-container: "#FFD8E4" on-tertiary-container: "#31111D" error: "#B3261E" on-error: "#FFFFFF" error-container: "#F9DEDC" on-error-container: "#410E0B" background: "#FFFBFE" on-background: "#1C1B1F" surface: "#FFFBFE" on-surface: "#1C1B1F" surface-variant: "#E7E0EC" on-surface-variant: "#49454F" surface-dim: "#DDD8E3" surface-bright: "#FFFBFE" surface-container-lowest: "#FFFFFF" surface-container-low: "#F7F2FA" surface-container: "#F3EDF7" surface-container-high: "#ECE6F0" surface-container-highest: "#E6E0E9" inverse-surface: "#313033" inverse-on-surface: "#F4EFF4" outline: "#79747E" outline-variant: "#CAC4D0" shadow: "#000000" scrim: "#000000" dark: primary: "#D0BCFF" on-primary: "#381E72" primary-container: "#4F378B" on-primary-container: "#EADDFF" inverse-primary: "#6750A4" secondary: "#CCC2DC" on-secondary: "#332D41" secondary-container: "#4A4458" on-secondary-container: "#E8DEF8" tertiary: "#EFB8C8" on-tertiary: "#492532" tertiary-container: "#633B48" on-tertiary-container: "#FFD8E4" error: "#F2B8B5" on-error: "#601410" error-container: "#8C1D18" on-error-container: "#F9DEDC" background: "#1C1B1F" on-background: "#E6E1E5" surface: "#1C1B1F" on-surface: "#E6E1E5" surface-variant: "#49454F" on-surface-variant: "#CAC4D0" surface-dim: "#141218" surface-bright: "#3B383E" surface-container-lowest: "#0F0D13" surface-container-low: "#1D1B20" surface-container: "#211F26" surface-container-high: "#2B2930" surface-container-highest: "#36343B" inverse-surface: "#E6E1E5" inverse-on-surface: "#313033" outline: "#938F99" outline-variant: "#49454F" shadow: "#000000" scrim: "#000000"
typography: typeface: brand: Roboto plain: Roboto weights: [400, 500, 700] scale: display-large: fontFamily: brand fontSize: 57px fontWeight: 400 lineHeight: 64px letterSpacing: -0.25px display-medium: fontFamily: brand fontSize: 45px fontWeight: 400 lineHeight: 52px letterSpacing: 0px display-small: fontFamily: brand fontSize: 36px fontWeight: 400 lineHeight: 44px letterSpacing: 0px headline-large: fontFamily: brand fontSize: 32px fontWeight: 400 lineHeight: 40px letterSpacing: 0px headline-medium: fontFamily: brand fontSize: 28px fontWeight: 400 lineHeight: 36px letterSpacing: 0px headline-small: fontFamily: brand fontSize: 24px fontWeight: 400 lineHeight: 32px letterSpacing: 0px title-large: fontFamily: brand fontSize: 22px fontWeight: 400 lineHeight: 28px letterSpacing: 0px title-medium: fontFamily: brand fontSize: 16px fontWeight: 500 lineHeight: 24px letterSpacing: 0.15px title-small: fontFamily: brand fontSize: 14px fontWeight: 500 lineHeight: 20px letterSpacing: 0.1px body-large: fontFamily: plain fontSize: 16px fontWeight: 400 lineHeight: 24px letterSpacing: 0.5px body-medium: fontFamily: plain fontSize: 14px fontWeight: 400 lineHeight: 20px letterSpacing: 0.25px body-small: fontFamily: plain fontSize: 12px fontWeight: 400 lineHeight: 16px letterSpacing: 0.4px label-large: fontFamily: plain fontSize: 14px fontWeight: 500 lineHeight: 20px letterSpacing: 0.1px label-medium: fontFamily: plain fontSize: 12px fontWeight: 500 lineHeight: 16px letterSpacing: 0.5px label-small: fontFamily: plain fontSize: 11px fontWeight: 500 lineHeight: 16px letterSpacing: 0.5px
shape: corner-none: 0px corner-extra-small: 4px corner-small: 8px corner-medium: 12px corner-large: 16px corner-extra-large: 28px corner-full: 9999px
M3 Expressive add-ons (May 2025)
corner-large-increased: 20px corner-extra-large-increased: 32px corner-extra-extra-large: 48px
spacing: xs: 4px sm: 8px md: 16px lg: 24px xl: 32px 2xl: 48px
components: button-filled: backgroundColor: "{colors.light.primary}" textColor: "{colors.light.on-primary}" shape: "{shape.corner-full}" typography: "{typography.scale.label-large}" button-outlined: backgroundColor: "transparent" textColor: "{colors.light.primary}" borderColor: "{colors.light.outline}" shape: "{shape.corner-full}" typography: "{typography.scale.label-large}" button-tonal: backgroundColor: "{colors.light.secondary-container}" textColor: "{colors.light.on-secondary-container}" shape: "{shape.corner-full}" typography: "{typography.scale.label-large}" fab: backgroundColor: "{colors.light.primary-container}" iconColor: "{colors.light.on-primary-container}" shape: "{shape.corner-large}" extended-fab: backgroundColor: "{colors.light.primary-container}" textColor: "{colors.light.on-primary-container}" shape: "{shape.corner-extra-large}" card: backgroundColor: "{colors.light.surface-container}" textColor: "{colors.light.on-surface}" shape: "{shape.corner-medium}" dialog: backgroundColor: "{colors.light.surface-container-high}" textColor: "{colors.light.on-surface}" shape: "{shape.corner-extra-large}" chip: backgroundColor: "{colors.light.surface-variant}" textColor: "{colors.light.on-surface-variant}" borderColor: "{colors.light.outline}" shape: "{shape.corner-small}" text-field: backgroundColor: "{colors.light.surface-container-highest}" textColor: "{colors.light.on-surface}" labelColor: "{colors.light.on-surface-variant}" activeIndicatorColor: "{colors.light.primary}" shape: "{shape.corner-extra-small}" navigation-bar: backgroundColor: "{colors.light.surface-container}" activeIndicatorColor: "{colors.light.secondary-container}" activeIconColor: "{colors.light.on-secondary-container}" inactiveIconColor: "{colors.light.on-surface-variant}" snackbar: backgroundColor: "{colors.light.inverse-surface}" textColor: "{colors.light.inverse-on-surface}" actionColor: "{colors.light.inverse-primary}" shape: "{shape.corner-extra-small}"
Overview
Material Design 3 is Google's current design system. Its visual language is expressive, adaptive, and accessible: rounded forms, tonal color, and a three-tier token architecture that allows a UI to respond to user color preferences at runtime.
The system is defined by four core decisions: a tonal palette-based color system, a five-role typescale, a named shape scale, and a semantic token layer that separates design intent from concrete values.
M3 Expressive (May 2025) extends the system with 35 abstract shapes and shape morphing (Compose and Android), 15 emphasized typescale styles for editorial moments, and 3 new corner radius tokens.
M3 is well-suited for: consumer apps, Google ecosystem products, cross-platform (Android/iOS/Web/Flutter), accessibility-first design, and any product that wants to support Dynamic Color or user-personalized theming.
Token Architecture
M3 organizes tokens into three tiers:
Reference tokens (--md-ref-*) — raw palette values. Every tone of every key color (0–100), typeface names, fixed spacing. Set once per theme; never used directly in components.
System tokens (--md-sys-*) — semantic roles. Color roles, typescale definitions, shape values. These are the public API — what components consume and what product teams override to apply brand.
Component tokens (--md-comp-* / --md-<component>-*) — scoped to a single component type. Alias system tokens. The upgrade-safe way to customize one component without affecting others.
The cascade: change a reference palette → all system tokens that draw from it update automatically → all components that use those system tokens update automatically.
Colors
The color system is built on tonal palettes: for each key color, a full range from tone 0 (black) to tone 100 (white) is generated using the HCT color space (Hue, Chroma, Tone). From these palettes, semantic roles are assigned.
Key colors — the five inputs that generate the full scheme:
- Primary: Main brand color. High-emphasis interactive elements.
- Secondary: Supporting accent. Lower-emphasis components.
- Tertiary: Contrasting accent for differentiation and expressive moments.
- Error: Exclusively for error and destructive states. Never repurpose.
- Neutral: Drives all surface and background colors.
Role families:
- Primary/secondary/tertiary each generate 4 standard roles:
*,on-*,*-container,on-*-container - Surface family: 5 container steps (
surface-container-lowest→surface-container-highest), plussurface-dimandsurface-brightadd-ons for consistent brightness control across themes - Outline:
outlinefor interactive component borders;outline-variantfor decorative dividers only - Inverse roles:
inverse-surface,inverse-on-surface,inverse-primaryfor components like snackbars that invert the surrounding theme
The on-* pattern is M3's primary accessibility mechanism. Every surface role has a paired on-* role for text and icons placed on it. These pairs always meet WCAG AA contrast. Never place content using a role that isn't the correct on-* partner for its background.
Three contrast levels (May 2025): Standard (default), Medium (≥ 3:1), High (7:1). Color roles are pre-calculated for all three levels. Use *-container / on-*-container pairings in custom components to inherit contrast level support automatically.
Dark theme uses the same role names — only the tone assignments change (e.g. primary uses tone 40 in light, tone 80 in dark). Token names are constant across themes.
Typography
Two typeface roles: brand (display, headline, title — expressive) and plain (body, label — readable). Both default to Roboto; customize globally via --md-ref-typeface-brand and --md-ref-typeface-plain. Load all three weights (400, 500, 700) for any font you configure.
Five roles × three sizes = 15 baseline styles. M3 Expressive adds 15 emphasized styles (same roles/sizes, heavier expressive weight) for editorial moments — available in Android/Compose/Flutter; web support pending.
Role selection follows content purpose, not desired visual size:
- Display (57/45/36px): Hero text, splash screens. One instance per view maximum.
- Headline (32/28/24px): Page and section titles, dialog headers.
- Title (22/16/14px): Component-level headings — card titles, app bar labels, list headers.
- Body (16/14/12px): Long-form readable content. Body Large for prose, Medium for UI descriptions.
- Label (14/12/11px): All utility text — button labels, field labels, captions, chip text.
Letter-spacing is significant for small sizes: Label Medium and Small both use 0.5px tracking to compensate for small size at reading distance.
Shape
Shape uses a named scale. The seven standard steps plus three M3 Expressive add-ons:
| Token | Value | Default component usage |
|---|---|---|
corner-none | 0px | Data tables, square containers |
corner-extra-small | 4px | Chips, menus, tooltips, text fields, snackbars |
corner-small | 8px | Outlined text fields |
corner-medium | 12px | Cards |
corner-large | 16px | Navigation drawers, FABs |
corner-extra-large | 28px | Extended FABs, dialogs, bottom sheets |
corner-full | 9999px | Buttons, badges, search bars |
corner-large-increased (Expressive) | 20px | — |
corner-extra-large-increased (Expressive) | 32px | — |
corner-extra-extra-large (Expressive) | 48px | — |
Shape communicates component personality: pill shapes invite interaction; extra-large suggests prominence; medium/small is functional. M3 Expressive also introduces shape morphing — animating between shapes in response to interaction states or environmental changes.
Use shapes from the named scale. Inventing arbitrary values creates visual noise. Global shape can be adapted for brand personality: reducing all radii toward small/none creates a formal, utilitarian character; keeping defaults or increasing toward extra-large/full creates friendly, expressive design.
Components
Filled button — Primary action. primary fill, on-primary text, label-large type, pill shape. The highest-emphasis action on a surface.
Tonal button — Secondary action with more visual weight than outlined. secondary-container fill, on-secondary-container text, pill shape.
Outlined button — Low-emphasis secondary action. Transparent fill, primary text and outline border, pill shape.
FAB — Floating action button. primary-container fill, on-primary-container icon, large corner radius (16px). Extended FABs use extra-large (28px).
Card — Container surface. surface-container fill, on-surface text, medium corners (12px). Elevated cards may use surface-container-low.
Dialog — Modal overlay. surface-container-high fill, on-surface text, extra-large corners (28px). Action buttons inside use standard button tokens.
Chip — Compact filter or selection. surface-variant fill with outline border, on-surface-variant text, small corners (8px).
Text field — Input surface. surface-container-highest fill, extra-small corners (4px). Active indicator uses primary; label uses on-surface-variant.
Navigation bar — Bottom navigation. surface-container background. Active indicator: secondary-container. Active icon: on-secondary-container. Inactive icon: on-surface-variant.
Snackbar — Transient notification. Uses inverse roles: inverse-surface background, inverse-on-surface text, inverse-primary action. extra-small corners.
Do's and Don'ts
Do:
- Generate your full color scheme from a single brand seed using Material Theme Builder or
material-color-utilities - Always use
on-*roles for text and icons on colored surfaces — these are pre-calculated for contrast - Use
*-containerroles for larger, lower-emphasis surfaces; reserve non-container roles for high-emphasis interactive elements - Load all three font weights (400, 500, 700) for any typeface you configure
- Apply shape from the named scale — don't invent arbitrary pixel values outside the scale
- Provide both light and dark color token sets — use the same token names, different tone assignments
Don't:
- Use reference palette tokens (
--md-ref-palette-*) directly in component styles — this bypasses the semantic layer and breaks theme switching - Hard-code hex values in component styles — always reference system tokens
- Mix M2 class names or token conventions (
mdc-typography--headline1, elevation overlays) with M3 tokens - Use Display or Headline typescale for body content, even for large body text
- Override all shapes to 0px globally unless a strictly flat aesthetic is intentional and applied consistently
- Repurpose
errorcolor roles for anything other than errors and destructive states