| name | Google Material Design 3 (M3 Expressive) |
| description | Material Design 3 uses dynamic color from seed colors, 35+ shape variants, and motion physics for personal, expressive, accessible UI. Trigger for Google ecosystem apps, Android, web products needing modern component library with adaptive layouts and AR/spatial support. |
Google Material Design 3 (M3 Expressive Update)
What Is Material Design 3?
Material Design 3 is Google's design system emphasizing personalization through dynamic color, expressivity via shape variants, and accessibility-first component design. The M3 Expressive update (2024) adds advanced motion physics, spatial/AR support, and expanded shape token library (35+ variants). Content is king—all design decisions fade into the background to highlight user content.
Core Design Principles
Personal Through Color: M3's dynamic color system generates palettes from a single seed color, adapting across 12 key colors (primary, secondary, tertiary, error) + neutral grays. This creates brand-aligned, personally-relevant interfaces. Never hardcode colors—always derive from seed. Change seed in one place; entire app updates.
Expressive Through Shape: Shape tokens (0%, 25%, 50%, 75%, 100% corner radii) allow consistent yet varied expression. A "small" shape (25% radius) might be 4px on small buttons but 12px on large cards—shape scales with component size, maintaining visual rhythm.
Motion Literacy: Motion serves purpose, not decoration. Standard easing is cubic-bezier(0.4, 0, 0.2, 1) (Material's deceleration curve). Use it for entrances (300ms), exits (200ms), state changes (250ms). Fast exits feel snappy; slow entrances feel premium.
Accessible by Default: All colors meet WCAG AA minimum (4.5:1 for text on backgrounds). Components include ARIA labels, keyboard navigation, focus indicators, and reduced-motion support built-in.
Visual Language
Dynamic Color System
Seed color: #6750A4 (Purple)
Generated palette:
- Primary: #6750A4 (used for main actions)
- Secondary: #625B71 (supporting actions)
- Tertiary: #7D5260 (accent, highlights)
- Error: #B3261E (destructive actions)
- On-Primary: #FFFFFF (text on primary backgrounds)
- Neutral (Gray 1-99): #FFFBFE to #1C1B1F
Typography
- Font family: Roboto (system font on Android), -apple-system on iOS/Web
- Scale: 16 weights (12px to 32px)
- Body Small: 12px / 16px line height / Regular
- Body Medium: 14px / 20px line height / Regular
- Body Large: 16px / 24px line height / Regular
- Headline Small: 24px / 32px line height / Bold
- Letter spacing: 0.5px for small text, 0px for body/headline
Spacing Grid
- 8px base unit: All spacing in multiples of 8px (8, 16, 24, 32, 40, 48, 56, 64)
- Component padding: 16px standard (buttons, cards, dialogs)
- Baseline grid alignment: Content aligns to 4px baselines for consistent text spacing
Elevation (Material's depth system)
- Level 0: No shadow (flat)
- Level 1: 0 0 3px rgba(0,0,0,0.12), 0 1px 3px rgba(0,0,0,0.08) — cards, floating text
- Level 2: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23) — floating action buttons
- Level 3: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23) — dialogs, menus
- Level 4: 0 15px 25px rgba(0,0,0,0.15), 0 15px 25px rgba(0,0,0,0.15) — modals
Shape Tokens
- Shape.None: 0% (no rounding) — dividers, full-width containers
- Shape.ExtraSmall: 4px — small buttons, chips
- Shape.Small: 8px — input fields, standard buttons
- Shape.Medium: 12px — cards, FABs
- Shape.Large: 16px — large cards, bottom sheets
- Shape.ExtraLarge: 28px — full-height modals with rounded tops
Component Patterns
Material Button (3 variants)
<button className="md3-button md3-button--filled">
Save Changes
</button>
<button className="md3-button md3-button--outlined">
Cancel
</button>
<button className="md3-button md3-button--text">
Learn More
</button>
<style>
.md3-button {
padding: 10px 24px;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
border: none;
cursor: pointer;
transition: all 250ms cubic-bezier(0.4, 0, 0.2, 1);
display: inline-flex;
align-items: center;
gap: 8px;
}
.md3-button--filled {
background-color: #6750A4;
color: white;
}
.md3-button--filled:hover {
background-color: #5A4496;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16);
}
.md3-button--outlined {
border: 1px solid #79747E;
background: transparent;
color: #6750A4;
}
.md3-button--text {
background: transparent;
color: #6750A4;
}
.md3-button:active {
transform: scale(0.98);
}
@media (prefers-reduced-motion: reduce) {
.md3-button {
transition: none;
}
}
</style>
Material Card with Image
<div className="md3-card">
<img src="content.jpg" alt="Card image" className="md3-card__media">
<div className="md3-card__content">
<h3 className="md3-headline-small">Card Title</h3>
<p className="md3-body-medium">Supporting text that describes the card content.</p>
</div>
<div className="md3-card__actions">
<button className="md3-button md3-button--text">Action 1</button>
<button className="md3-button md3-button--text">Action 2</button>
</div>
</div>
<style>
.md3-card {
background: var(--surface);
border-radius: 12px;
overflow: hidden;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 3px rgba(0, 0, 0, 0.08);
display: flex;
flex-direction: column;
}
.md3-card__media {
width: 100%;
height: 200px;
object-fit: cover;
}
.md3-card__content {
padding: 16px;
}
.md3-card__actions {
padding: 8px 16px;
display: flex;
gap: 8px;
justify-content: flex-end;
}
</style>
Code Generation Guidance
Color Token Usage: Always generate colors dynamically. In React using Material UI:
import { createTheme, ThemeProvider } from '@mui/material/styles';
const theme = createTheme({
palette: {
primary: { main: '#6750A4' },
secondary: { main: '#625B71' },
},
});
Shape Token Scaling: Larger components get larger radius. If a button is 48px tall, use 12px radius (25%). If a card is full-width, use 16px radius (shape.large).
Motion Pattern: Entrance animations use deceleration (slower at end), exits use acceleration (faster at end):
@keyframes enter {
from { opacity: 0; transform: scale(0.95); }
to { opacity: 1; transform: scale(1); }
}
.component-enter {
animation: enter 300ms cubic-bezier(0.4, 0, 0.2, 1);
}
@keyframes exit {
from { opacity: 1; transform: scale(1); }
to { opacity: 0; transform: scale(0.95); }
}
.component-exit {
animation: exit 200ms cubic-bezier(0.4, 0, 0.2, 1);
}
Responsive Shapes: Adjust shape tokens based on screen size:
@media (max-width: 600px) {
.card { border-radius: 8px; }
}
@media (min-width: 1200px) {
.card { border-radius: 16px; }
}
Accessibility Notes
- Color contrast: All text on color backgrounds must meet 4.5:1 ratio. Use generated
on- colors (onPrimary, onSecondary).
- Focus indicators: Always provide visible focus rings (2px offset, primary color).
- Touch targets: Minimum 48px × 48px for interactive elements.
- Reduced motion: Replace animations with instant state changes when
prefers-reduced-motion is set.
- ARIA labels: Buttons must have descriptive text or
aria-label attributes.
Examples
Example 1: Sign-Up Form
Input: Create a sign-up form with Material Design 3 components (text inputs, filled button, validation).
Output:
function SignUpForm() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
return (
<div className="md3-form-container">
<h1 className="md3-headline-small">Create Account</h1>
<div className="md3-input-group">
<label htmlFor="email" className="md3-label">Email</label>
<input
id="email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="md3-input"
placeholder="you@example.com"
/>
</div>
<div className="md3-input-group">
<label htmlFor="password" className="md3-label">Password</label>
<input
id="password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
className="md3-input"
placeholder="Min. 8 characters"
/>
</div>
{error && <div className="md3-error-message">{error}</div>}
<button
className="md3-button md3-button--filled"
onClick={() => setError('') || alert('Signed up!')}
>
Sign Up
</button>
</div>
);
}
<style>
.md3-form-container {
max-width: 400px;
padding: 24px;
background: var(--surface);
border-radius: 12px;
}
.md3-input-group {
margin-bottom: 16px;
display: flex;
flex-direction: column;
}
.md3-label {
font-size: 12px;
font-weight: 600;
margin-bottom: 8px;
color: var(--on-surface);
}
.md3-input {
border: 1px solid #79747E;
border-radius: 8px;
padding: 12px 16px;
font-size: 14px;
transition: border-color 250ms cubic-bezier(0.4, 0, 0.2, 1);
}
.md3-input:focus {
outline: none;
border-color: #6750A4;
box-shadow: 0 0 0 3px rgba(103, 80, 164, 0.1);
}
.md3-error-message {
color: #B3261E;
font-size: 12px;
margin-bottom: 12px;
}
</style>
Example 2: Navigation Bar
Input: Build a bottom navigation bar with Material Design 3 indicators for active state.
Output:
function BottomNav() {
const [active, setActive] = useState('home');
return (
<nav className="md3-bottom-nav">
{['home', 'search', 'favorites', 'profile'].map(item => (
<button
key={item}
className={`md3-nav-item ${active === item ? 'active' : ''}`}
onClick={() => setActive(item)}
>
<div className="md3-nav-icon">
{/* Icon SVG here */}
</div>
<span className="md3-label-small">{item}</span>
</button>
))}
</nav>
);
}
<style>
.md3-bottom-nav {
display: flex;
justify-content: space-around;
align-items: center;
background: var(--surface);
border-top: 1px solid #E7E0EC;
height: 80px;
position: fixed;
bottom: 0;
width: 100%;
}
.md3-nav-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
border: none;
background: none;
cursor: pointer;
color: #49454E;
transition: color 250ms cubic-bezier(0.4, 0, 0.2, 1);
}
.md3-nav-item.active {
color: #6750A4;
}
.md3-nav-item.active .md3-nav-icon {
background: rgba(103, 80, 164, 0.1);
border-radius: 12px;
padding: 8px;
}
</style>
When to use M3: Google ecosystem apps (Gmail, Drive), Material UI projects, Android apps, design-forward web products. Avoid: Apple ecosystem (use Liquid Glass/SF Symbols), Microsoft products (use Fluent).