Semantic Colors
Semantic color tokens provide contextual meaning to color usage, organizing colors by where and how they're used rather than their visual appearance.
Token Structure
Semantic colors follow a consistent hierarchy:
{ux}.{context}.{nature}.{state?}
Examples:
action.background.primary.default
input.text.error.focused
display.border.muted.hover
UX Context Categories
Action Context
Usage: Interactive elements that trigger user actions
Colors for buttons, CTAs, links, and other actionable elements:
action: {
background: {
primary: {
default: core.colors.main,
hover: core.colors.complimentary,
active: core.colors.accent
},
secondary: {
default: core.colors.gray200,
hover: core.colors.white,
active: core.colors.darkNeutral
},
accent: {
default: core.colors.accent,
hover: 'brightness(110%)',
active: core.colors.teal600
},
negative: {
default: core.colors.red700
}
},
text: {
primary: { default: core.colors.black },
secondary: {
default: core.colors.white,
active: core.colors.complimentary
},
accent: { default: core.colors.white },
negative: { default: core.colors.white }
},
border: {
primary: { default: core.colors.main },
secondary: { default: core.colors.black },
muted: { default: core.colors.gray600 }
}
}
Component Examples:
// Primary button
<Button variant="primary">
{/* Uses action.background.primary.default */}
{/* Uses action.text.secondary.default */}
</Button>
// Destructive button
<Button variant="destructive">
{/* Uses action.background.negative.default */}
{/* Uses action.text.negative.default */}
</Button>
Input Context
Usage: Form elements and data entry components
Colors for inputs, selects, checkboxes, and form validation:
input: {
background: {
primary: { default: core.colors.white },
muted: {
default: core.colors.gray200,
disabled: core.colors.gray300
}
},
text: {
primary: { default: core.colors.black },
secondary: { default: core.colors.darkNeutral },
muted: { default: core.colors.gray600 },
accent: { default: core.colors.accent },
negative: { default: core.colors.red700 }
},
border: {
default: {
default: core.colors.gray300,
focused: core.colors.accent
},
muted: { default: core.colors.gray200 },
negative: { default: core.colors.red700 }
}
}
Component Examples:
// Standard input
<Input>
{/* Uses input.background.primary.default */}
{/* Uses input.border.default.default */}
</Input>
// Error state input
<Input variant="error">
{/* Uses input.border.negative.default */}
{/* Uses input.text.negative.default for helper text */}
</Input>
Display Context
Usage: Content presentation and information display
Colors for text, cards, containers, and data presentation:
display: {
background: {
primary: { default: core.colors.main },
secondary: { default: core.colors.white },
muted: { default: core.colors.gray200 }
},
text: {
primary: { default: core.colors.black },
secondary: { default: core.colors.darkNeutral },
muted: {
default: core.colors.gray600,
active: core.colors.gray200
},
accent: { default: core.colors.accent },
negative: { default: core.colors.red700 }
},
border: {
primary: { default: core.colors.main },
secondary: { default: core.colors.black },
muted: {
default: core.colors.gray600,
active: core.colors.darkNeutral
}
}
}
Component Examples:
// Content card
<Card>
{/* Uses display.background.secondary.default */}
{/* Uses display.border.muted.default */}
</Card>
// Primary text
<Text variant="body">
{/* Uses display.text.primary.default */}
</Text>
// Secondary text
<Text variant="caption">
{/* Uses display.text.muted.default */}
</Text>
Feedback Context
Usage: Status communication and user feedback
Colors for alerts, notifications, and status indicators:
feedback: {
background: {
primary: { default: core.colors.white },
positive: { default: core.colors.teal600 },
negative: { default: core.colors.red700 },
caution: { default: core.colors.amber600 }
},
text: {
primary: { default: core.colors.white },
secondary: { default: core.colors.black },
positive: { default: core.colors.white },
negative: { default: core.colors.white },
caution: { default: core.colors.white }
},
border: {
positive: { default: core.colors.teal600 },
negative: { default: core.colors.red700 },
caution: { default: core.colors.amber600 }
}
}
Component Examples:
// Success alert
<Alert variant="success">
{/* Uses feedback.background.positive.default */}
{/* Uses feedback.text.positive.default */}
</Alert>
// Error notification
<Notification variant="error">
{/* Uses feedback.background.negative.default */}
{/* Uses feedback.text.negative.default */}
</Notification>
Navigation Context
Usage: Wayfinding and site navigation
Colors for menus, links, breadcrumbs, and navigation elements:
navigation: {
background: {
primary: { default: core.colors.complimentary },
muted: { default: core.colors.complimentary }
},
text: {
primary: { default: core.colors.black },
accent: { default: core.colors.darkNeutral },
muted: { default: core.colors.gray600 },
negative: { default: core.colors.red700 }
},
border: {
primary: { default: core.colors.black },
muted: { default: core.colors.gray600 }
}
}
Component Examples:
// Navigation link
<Link>
{/* Uses navigation.text.primary.default */}
{/* Uses navigation.text.accent.default on :visited */}
</Link>
// Main navigation
<Nav>
{/* Uses navigation.background.primary.default */}
</Nav>
Interaction States
All interactive semantic tokens include state variations:
State Modifiers
default
: Base statehover
: Mouse hover stateactive
: Pressed/clicked statefocused
: Keyboard focus statedisabled
: Disabled stateselected
: Selected state (for toggles)
State Examples
// Complete button state system
action: {
background: {
primary: {
default: core.colors.main,
hover: 'brightness(110%)', // Lighter on hover
active: core.colors.accent, // Different color on press
disabled: core.colors.gray300 // Muted when disabled
}
}
}
Theme Mode Support
Semantic tokens adapt to different theme modes (light/dark) by referencing different core tokens:
// Light mode theme
display: {
background: {
primary: { default: core.colors.white },
secondary: { default: core.colors.gray100 }
},
text: {
primary: { default: core.colors.black }
}
}
// Dark mode theme (same structure, different core values)
display: {
background: {
primary: { default: core.colors.black },
secondary: { default: core.colors.gray900 }
},
text: {
primary: { default: core.colors.white }
}
}
Implementation Patterns
Component Styling
// Using semantic tokens in custom components
const StyledCard = styled.div`
background-color: ${(props) =>
props.theme.colors.display.background.secondary.default};
border: 1px solid
${(props) => props.theme.colors.display.border.muted.default};
color: ${(props) => props.theme.colors.display.text.primary.default};
`;
// With Theme UI sx prop
<Box
sx={{
backgroundColor: 'display.background.secondary.default',
borderColor: 'display.border.muted.default',
color: 'display.text.primary.default',
}}
>
Content
</Box>;
Responsive Usage
// Semantic tokens work with responsive arrays
<Box
sx={{
backgroundColor: [
'display.background.primary.default',
'display.background.secondary.default',
],
color: ['display.text.primary.default', 'display.text.secondary.default'],
}}
>
Responsive semantic colors
</Box>
Accessibility Considerations
Semantic tokens ensure accessible color usage:
- Sufficient contrast: Color combinations meet WCAG guidelines
- Consistent relationships: Same semantic meaning maintains contrast across themes
- Focus indicators: Dedicated focus state colors for keyboard navigation
- Error communication: Clear error state colors for form validation
Contrast Testing
// Semantic tokens maintain contrast ratios
action.background.primary.default + action.text.secondary.default = 4.5:1 (AA)
input.background.primary.default + input.text.primary.default = 7:1 (AAA)
display.background.secondary.default + display.text.primary.default = 12:1 (AAA)
Best Practices
Token Usage
- Use semantic over core: Always prefer semantic tokens in components
- Match context to usage: Use
action.*
for buttons,input.*
for forms - Include all states: Define hover, focus, disabled states for interactive elements
- Test across themes: Ensure tokens work in all theme variations
Component Integration
// Good: Using appropriate semantic context
<Button sx={{
backgroundColor: 'action.background.primary.default' // ✅ Correct context
}} />
// Avoid: Using wrong context
<Button sx={{
backgroundColor: 'display.background.primary.default' // ❌ Wrong context
}} />
// Bad: Using core tokens directly
<Button sx={{
backgroundColor: 'main' // ❌ Too direct
}} />
Next Steps
- Component Implementation: See semantic colors in action