Material Design 3 and Design Tokens
Material Design 3 and Design Tokens
Material Design is a design system Google announced in 2014. It went through a major revision in 2021 with Material 3 (M3).
1. The history of Material Design
| Version | Announced | Event |
|---|---|---|
| Material 1 | 2014 (Google I/O) | Announced by Matías Duarte. Paper and ink metaphor. |
| Material 2 | 2018 | Component standardization. Material Theming. |
| Material 3 | 2021 | "Material You". Dynamic color (HCT color space). |
The major changes of Material 3 are summarized in two points.
① Dynamic color — automatically generates the entire color palette from a user wallpaper (Android 12+) or a single source color
② Design tokens as a first-class model — components no longer hard-code their attributes; they reference tokens instead
2. Design tokens
The W3C Design Tokens Community Group (DTCG) has been working on standardization since 2021. A token is a small named value of a design decision.
{
"color": {
"primary": { "$value": "#6750A4", "$type": "color" }
},
"spacing": {
"sm": { "$value": "8px", "$type": "dimension" },
"md": { "$value": "16px", "$type": "dimension" }
}
}
Tools like Style Dictionary (Amazon) translate this JSON into CSS variables, Swift, and Kotlin.
3. M3 token categories
| Category | Example tokens |
|---|---|
| Color | md.sys.color.primary, md.sys.color.on-primary, md.sys.color.surface |
| Typography | md.sys.typescale.headline-large, md.sys.typescale.body-medium |
| Shape | md.sys.shape.corner.small, md.sys.shape.corner.large |
| Elevation | md.sys.elevation.level0~`level5` |
| Motion | md.sys.motion.duration.short2, md.sys.motion.easing.standard |
| State | layer opacity for hover/focus/pressed/dragged |
Tokens are layered into three tiers.
- ref (reference) — atomic value.
md.ref.palette.primary40 = #6750A4. - sys (system) — token with semantic meaning.
md.sys.color.primary = ref.palette.primary40. - comp (component) — per component.
md.comp.button.filled.container.color = sys.color.primary.
Thanks to this layering, dark mode, dynamic color, and brand variants only need to swap the sys layer; components follow.
4. HCT color space
M3's dynamic color uses the HCT (Hue, Chroma, Tone) color space. Created by Google by combining CAM16 + L*, it is advantageous for accessibility (contrast ratio) calculations because perceived lightness becomes close when comparing within the same Tone.
The material-color-utilities (Google) library provides:
- Generate five tonal palettes (primary, secondary, tertiary, neutral, neutral-variant) from a single source color.
- 13 tone steps (0, 10, 20, ..., 100) per palette.
- Automatic mapping to light/dark schemes.
import { themeFromSourceColor, hexFromArgb } from "@material/material-color-utilities"
const theme = themeFromSourceColor(0xff6750a4)
const primary = hexFromArgb(theme.schemes.light.primary)
5. Motion tokens
M3 also tokenizes motion.
- Duration — short1
short4 (50200ms), medium1medium4 (250400ms), long1long4 (450600ms), extra-long. - Easing — standard, emphasized, emphasized-decelerate, emphasized-accelerate.
emphasized is defined as a curve that starts fast and ends gently (around cubic-bezier(0.2, 0.0, 0.0, 1.0)).
6. Paths to implement M3 in React
| Approach | Library | Notes |
|---|---|---|
| Component library | MUI (Material UI) v5/v6 | M2-based. v6 gradually adopting M3 tokens. Largest user base. |
| Web components | @material/web |
M3 web components built by Google. Use as <md-filled-button> from React. |
| Tokens only | material-color-utilities + custom components |
Combine with shadcn/Radix/Tailwind. |
| Tailwind integration | plugins like tailwindcss-material-colors |
Combine utilities with tokens. |
@material/web is reportedly in maintenance mode after v1.0 (2024) with no new feature development. As sustainable paths, two branches are often discussed: bringing in only the tokens and mapping them onto custom components, or following MUI's M3 support.
7. Other design systems
| System | Origin | Notes |
|---|---|---|
| Material 3 | Standard for Android/web. | |
| Apple HIG | Apple | iOS/macOS guidelines. |
| Microsoft Fluent 2 | Microsoft | Windows, Office. Fluent UI React. |
| Carbon Design System | IBM | Enterprise. |
| Atlassian Design System | Atlassian | |
| Polaris | Shopify | |
| Ant Design | Alibaba (2015) | Strong in Chinese enterprise. |
8. Headless + token model
A pattern frequently seen in the React ecosystem now:
- Radix UI (accessible headless components) + Tailwind (styles) + CSS variable tokens.
- Components are written in-house (or copied via shadcn).
- Tokens map M3-extracted colors to CSS variables.
A strength of this model is that it borrows tokens without locking into a design system.
9. Mapping M3 tokens to CSS variables
:root {
--md-primary: oklch(0.50 0.13 290);
--md-on-primary: oklch(1.00 0 0);
--md-surface: oklch(0.99 0.005 90);
--md-on-surface: oklch(0.15 0.01 90);
--md-outline: oklch(0.65 0.02 90);
--md-shape-sm: 4px;
--md-shape-md: 12px;
--md-shape-lg: 16px;
--md-easing-standard: cubic-bezier(0.2, 0, 0, 1);
--md-duration-short2: 100ms;
}
.dark {
--md-primary: oklch(0.78 0.13 290);
--md-on-primary: oklch(0.20 0.05 290);
--md-surface: oklch(0.18 0.01 90);
--md-on-surface: oklch(0.95 0.005 90);
}
10. Generating dynamic colors
import { argbFromHex, themeFromSourceColor, hexFromArgb }
from "@material/material-color-utilities"
const source = argbFromHex("#0061a4")
const theme = themeFromSourceColor(source)
const tokens = {
primary: hexFromArgb(theme.schemes.light.primary),
onPrimary: hexFromArgb(theme.schemes.light.onPrimary),
surface: hexFromArgb(theme.schemes.light.surface),
}
11. Common pitfalls
Mixing M2 and M3 — MUI tokens differ across minor versions. When M2 components and M3 components mix in one codebase, design consistency breaks.
Verifying contrast in dynamic color — HCT keeps tones aligned, but not every combination guarantees WCAG 4.5:1. Verify text/background pairs separately.
Token name churn — token names changed several times during M3 stabilization. Map to the official current names.
@material/web React integration — being a web component, it feels slightly off with React props/events. Wrappers like @lit-labs/react were often used.
Dark mode auto mapping — Material's light and dark tones are not a simple invert. Build a ref-palette and keep a separate sys mapping table.
Closing thoughts
Bringing in Material Design 3 wholesale makes the codebase heavy. Bringing in only the tokens and layering them onto custom components + Tailwind is a lighter path that still keeps consistency. Apply dynamic color in places where user freedom is high, and start ordinary apps with static tokens.
Next
- forms-zod
- bundlers
We refer to Material 3, Material Components GitHub, @material/web, material-color-utilities, W3C Design Tokens, Style Dictionary, MUI, and Radix UI.