| name | Microsoft Fluent Design System 2 |
| description | Microsoft Fluent 2 emphasizes light, depth, motion, material, and scale across Windows, iOS, Android, and web. Trigger for Microsoft ecosystem apps, Windows UI design, cross-platform products with strong accessibility requirements (WCAG AAA target), and apps needing token-based theming flexibility. |
Microsoft Fluent Design System 2
What Is Fluent Design 2?
Fluent Design System 2 is Microsoft's modern design language built on five pillars: Light (clarity through smart contrast), Depth (layered elevation), Motion (purposeful movement), Material (Acrylic/Mica translucency), and Scale (adaptive sizing). It spans Windows 11, Microsoft 365, Teams, Outlook, iOS, Android, and web. Fluent 2 prioritizes accessibility at AAA level, token-based theming for rapid adaptation, and a premium feel through translucent materials and intentional motion.
Core Design Principles
Light for Clarity: Fluent 2 uses carefully weighted color contrast (7:1 minimum) to make hierarchy obvious without relying on saturated colors. Text is never pure black—it's #1F1F1F in light mode, #FFFFFF in dark. Backgrounds are carefully tinted to create depth through contrast, not color saturation.
Depth Through Layering: Elevation isn't just shadows—it's a combination of shadow, color tint shift, and sometimes subtle translucency. Each elevation level (0-32pt) increases shadow radius, darkens tint, and lifts upward. A card at elevation 4 sits visually above one at elevation 2.
Motion With Purpose: Fluent's motion library is subtle but pervasive. Standard motion duration is 200-300ms with easing of cubic-bezier(0.33, 0, 0.67, 1) (gentle deceleration). Motion reveals, not distracts. Hover states elevate with shadow; focus states add a 2px border glow.
Material Translucency: Acrylic (for overlays, popovers) and Mica (for surfaces, panels) create premium, iOS-like effects. Acrylic allows 50% transparency with 20px blur; Mica is semi-opaque (15-30% opacity) with minimal blur, sitting behind content. Both respond to light mode/dark mode automatically.
Scale Adaptation: Fluent components scale from 40px (touch-small) to 64px (touch-large) based on input method. Keyboard and mouse users see compact 32px buttons; touch users see 48px. This adapts without explicit breakpoints—the OS signals input method.
Visual Language
Color Palette
Neutral colors (scalable theme):
- Foreground: #1F1F1F (dark) / #FFFFFF (light) — text
- Surface: #FFFFFF (dark mode #1F1F1F) — primary background
- Subtle: #F3F3F3 (dark: #2B2B2B) — secondary background
- Muted: #D4D4D4 (dark: #454545) — borders, dividers
Semantic colors:
- Primary: #0078D4 (Microsoft Blue) — actions, links
- Success: #107C10 (Green) — confirmations
- Warning: #FFB900 (Amber) — cautions
- Error: #D13438 (Red) — failures
Typography
- Font: Segoe UI (Windows), -apple-system (iOS), Roboto (Android), system-ui (web fallback)
- Sizes:
- Caption: 12px / 16px line height
- Body: 14px / 20px line height (baseline)
- Title: 18px / 26px line height / 600 weight
- Display: 28px / 36px line height / 700 weight
- Weight usage: 400 (body), 500 (buttons), 600 (labels), 700 (headings)
Spacing
- Base unit: 4px
- Common spacing: 8px (tight), 12px (standard), 16px (spacious), 24px (section), 32px (large section)
- Button padding: 8px 12px (compact), 12px 16px (standard)
- Card padding: 16px standard, 24px large
Elevation (Depth) System
- Level 0: No shadow, neutral background
- Level 4:
0 1px 2px rgba(0,0,0,0.05) + subtle tint shift
- Level 8:
0 2px 4px rgba(0,0,0,0.10) + more tint shift
- Level 16:
0 4px 8px rgba(0,0,0,0.15) — floating panels
- Level 24:
0 8px 16px rgba(0,0,0,0.20) — modals
- Level 32:
0 16px 32px rgba(0,0,0,0.25) — top-level overlays
Materials
- Mica (surfaces): Semi-opaque base (8-15% opacity layer), no blur, used for app backgrounds. Creates a frosted glass look without readability loss.
- Acrylic (overlays): 50% transparency + 20px Gaussian blur, used for flyouts, menus, context panels. Reveals content below while maintaining focus on overlay content.
Component Patterns
Fluent Button (Multiple Variants)
function FluentButton({ variant = 'primary', ...props }) {
const baseStyles = {
padding: '8px 16px',
borderRadius: '4px',
border: 'none',
fontSize: '14px',
fontWeight: '500',
cursor: 'pointer',
transition: 'all 200ms cubic-bezier(0.33, 0, 0.67, 1)',
minHeight: '32px',
display: 'inline-flex',
alignItems: 'center',
gap: '8px',
};
const variants = {
primary: {
...baseStyles,
background: '#0078D4',
color: '#FFFFFF',
'&:hover': { background: '#106EBE', boxShadow: '0 2px 4px rgba(0,0,0,0.10)' },
'&:active': { background: '#005A9E', transform: 'scale(0.98)' },
},
secondary: {
...baseStyles,
background: '#F3F3F3',
color: '#1F1F1F',
border: '1px solid #D4D4D4',
'&:hover': { background: '#EFEFEF', boxShadow: '0 1px 2px rgba(0,0,0,0.05)' },
},
subtle: {
...baseStyles,
background: 'transparent',
color: '#0078D4',
'&:hover': { background: 'rgba(0, 120, 212, 0.1)' },
},
};
return <button style={variants[variant]} {...props} />;
}
Acrylic Flyout Menu
import React, { useState } from 'react';
function FluentFlyout() {
const [visible, setVisible] = useState(false);
return (
<div className="flyout-container">
<button
className="flyout-trigger"
onClick={() => setVisible(!visible)}
>
More Options
</button>
{visible && (
<div className="flyout-menu acrylic-surface">
<a href="#" className="menu-item">Profile</a>
<a href="#" className="menu-item">Settings</a>
<hr style={{ margin: '8px 0', border: 'none', borderTop: '1px solid #D4D4D4' }} />
<a href="#" className="menu-item danger">Sign Out</a>
</div>
)}
</div>
);
}
<style>
.flyout-container {
position: relative;
}
.flyout-trigger {
padding: 8px 12px;
background: #0078D4;
color: white;
border: none;
border-radius: 4px;
font-size: 14px;
cursor: pointer;
transition: all 200ms cubic-bezier(0.33, 0, 0.67, 1);
}
.flyout-menu {
position: absolute;
top: 100%;
right: 0;
margin-top: 8px;
border-radius: 8px;
min-width: 160px;
z-index: 100;
animation: slideIn 200ms cubic-bezier(0.33, 0, 0.67, 1);
}
.acrylic-surface {
background: rgba(255, 255, 255, 0.5);
backdrop-filter: blur(20px);
border: 1px solid rgba(0, 0, 0, 0.08);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
}
@media (prefers-color-scheme: dark) {
.acrylic-surface {
background: rgba(28, 28, 28, 0.7);
border-color: rgba(255, 255, 255, 0.1);
}
}
.menu-item {
display: block;
padding: 12px 16px;
color: #1F1F1F;
text-decoration: none;
font-size: 14px;
transition: background 200ms cubic-bezier(0.33, 0, 0.67, 1);
}
.menu-item:hover {
background: rgba(0, 120, 212, 0.1);
}
.menu-item.danger {
color: #D13438;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateY(-8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
</style>
Mica Background Panel
.mica-panel {
background: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(3px);
border-radius: 8px;
border: 1px solid rgba(0, 0, 0, 0.05);
padding: 24px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
}
@media (prefers-color-scheme: dark) {
.mica-panel {
background: rgba(28, 28, 28, 0.8);
border-color: rgba(255, 255, 255, 0.08);
}
}
.card-on-mica {
background: #FFFFFF;
border-radius: 4px;
padding: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.10);
}
@media (prefers-color-scheme: dark) {
.card-on-mica {
background: #1F1F1F;
}
}
Code Generation Guidance
Fluent Motion Easing: Always use cubic-bezier(0.33, 0, 0.67, 1) (Fluent's standard ease) for interactive animations. This feels natural and responsive.
.fluent-animated {
transition: all 200ms cubic-bezier(0.33, 0, 0.67, 1);
}
.button:hover {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.10);
transform: translateY(-1px);
}
.button:focus {
outline: none;
box-shadow: 0 0 0 2px #0078D4;
}
Theme Tokens Pattern (React):
const theme = {
light: {
surface: '#FFFFFF',
foreground: '#1F1F1F',
primary: '#0078D4',
acrylic: 'rgba(255, 255, 255, 0.5)',
mica: 'rgba(255, 255, 255, 0.15)',
},
dark: {
surface: '#1F1F1F',
foreground: '#FFFFFF',
primary: '#0078D4',
acrylic: 'rgba(28, 28, 28, 0.7)',
mica: 'rgba(28, 28, 28, 0.8)',
},
};
const Button = ({ children }) => (
<button style={{ background: useTheme().primary }}>
{children}
</button>
);
Accessibility-First HTML:
<button aria-label="Open menu" class="fluent-button-primary">
Menu
</button>
<style>
.fluent-button:focus-visible {
outline: 2px solid #0078D4;
outline-offset: 2px;
}
</style>
Accessibility Notes
- Contrast: Fluent targets WCAG AAA (7:1 minimum) by default. Primary blue (#0078D4) on white achieves 8.5:1.
- Focus indicators: Always provide visible focus (2px outline, primary color) offset by 2px.
- Reduced motion: Replace material animations with instant state changes when
prefers-reduced-motion is set.
- Touch sizing: Buttons minimum 44px × 44px on touch devices (test with 48px padding).
- Alt text: All decorative materials (Acrylic, Mica) are CSS-only—content remains accessible underneath.
Examples
Example 1: Settings Panel with Mica Background
Input: Create a settings panel with Mica background, toggles, and dropdown selectors in Fluent style.
Output:
function SettingsPanel() {
const [theme, setTheme] = useState('auto');
const [notifications, setNotifications] = useState(true);
return (
<div className="mica-panel">
<h2 style={{ marginTop: 0, fontSize: '18px', fontWeight: '600' }}>
Preferences
</h2>
<div className="settings-group">
<label>
<span className="label-text">Theme</span>
<select
value={theme}
onChange={(e) => setTheme(e.target.value)}
className="fluent-select"
>
<option value="auto">Auto (system)</option>
<option value="light">Light</option>
<option value="dark">Dark</option>
</select>
</label>
</div>
<div className="settings-group">
<label className="toggle-label">
<input
type="checkbox"
checked={notifications}
onChange={(e) => setNotifications(e.target.checked)}
className="fluent-checkbox"
/>
<span>Enable notifications</span>
</label>
</div>
<div style={{ marginTop: '24px', display: 'flex', gap: '12px' }}>
<button className="fluent-button fluent-button--primary">Save</button>
<button className="fluent-button fluent-button--secondary">Cancel</button>
</div>
</div>
);
}
<style>
.mica-panel {
background: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(3px);
border-radius: 8px;
padding: 24px;
max-width: 400px;
}
.settings-group {
margin-bottom: 16px;
padding-bottom: 16px;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}
.label-text {
display: block;
font-weight: 500;
margin-bottom: 8px;
color: #1F1F1F;
}
.fluent-select {
width: 100%;
padding: 8px 12px;
border: 1px solid #D4D4D4;
border-radius: 4px;
font-size: 14px;
background: #FFFFFF;
color: #1F1F1F;
}
.fluent-checkbox {
margin-right: 8px;
cursor: pointer;
}
.toggle-label {
display: flex;
align-items: center;
cursor: pointer;
font-size: 14px;
}
</style>
Example 2: Acrylic Command Palette (Search)
Input: Build an Acrylic overlay search/command palette with keyboard focus and results list.
Output:
function CommandPalette() {
const [open, setOpen] = useState(false);
const [search, setSearch] = useState('');
const results = [
{ label: 'Open Settings', icon: '⚙️' },
{ label: 'Create New Document', icon: '📄' },
{ label: 'Search Files', icon: '🔍' },
].filter(r => r.label.toLowerCase().includes(search.toLowerCase()));
return (
<>
{open && (
<div className="command-palette-overlay" onClick={() => setOpen(false)}>
<div className="command-palette" onClick={(e) => e.stopPropagation()}>
<input
autoFocus
type="text"
value={search}
onChange={(e) => setSearch(e.target.value)}
placeholder="Search commands..."
className="command-input"
/>
<div className="command-results">
{results.map((result, idx) => (
<div key={idx} className="command-item">
<span>{result.icon}</span>
<span>{result.label}</span>
</div>
))}
</div>
</div>
</div>
)}
<button
onClick={() => setOpen(true)}
className="fluent-button fluent-button--primary"
>
Search (Ctrl+K)
</button>
</>
);
}
<style>
.command-palette-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.4);
display: flex;
align-items: flex-start;
padding-top: 80px;
z-index: 1000;
}
.command-palette {
background: rgba(255, 255, 255, 0.5);
backdrop-filter: blur(20px);
border-radius: 8px;
border: 1px solid rgba(0, 0, 0, 0.08);
width: 90%;
max-width: 500px;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
}
.command-input {
width: 100%;
padding: 16px;
border: none;
background: transparent;
font-size: 14px;
color: #1F1F1F;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}
.command-input:focus {
outline: none;
}
.command-results {
max-height: 300px;
overflow-y: auto;
}
.command-item {
padding: 12px 16px;
display: flex;
align-items: center;
gap: 12px;
cursor: pointer;
transition: background 200ms cubic-bezier(0.33, 0, 0.67, 1);
}
.command-item:hover {
background: rgba(0, 120, 212, 0.1);
}
</style>
When to use Fluent 2: Microsoft ecosystem apps (Teams, Outlook, Microsoft 365), Windows desktop applications, accessibility-critical products (AAA compliance), cross-platform apps needing cohesive design across Windows/iOS/Android. Avoid: consumer social apps (use Material Design), Apple-only products (use Liquid Glass).