The Theme UI theming system provides a comprehensive approach to design systems with color modes, design tokens, theme specification compliance, and component variants. It enables consistent, constraint-based design across applications with built-in support for light/dark modes and theme customization.
The ThemeUIProvider component provides theme context to all child components and manages color mode state.
/**
* Main theme provider component with color mode support
* @param theme - Theme object following Theme UI specification
* @param children - Child components that will receive theme context
*/
interface ThemeUIProviderProps {
theme: Theme;
children: React.ReactNode;
}
function ThemeUIProvider(props: ThemeUIProviderProps): JSX.Element;
// Deprecated alias - use ThemeUIProvider instead
function ThemeProvider(props: ThemeUIProviderProps): JSX.Element;Usage Examples:
import { ThemeUIProvider } from 'theme-ui'
const theme = {
colors: {
text: '#000',
background: '#fff',
primary: '#07c',
secondary: '#30c',
modes: {
dark: {
text: '#fff',
background: '#000',
primary: '#0cf',
secondary: '#f0c'
}
}
},
fonts: {
body: 'system-ui, sans-serif',
heading: '"Avenir Next", sans-serif',
monospace: 'Menlo, monospace'
}
}
export default function App({ children }) {
return (
<ThemeUIProvider theme={theme}>
{children}
</ThemeUIProvider>
)
}The theme object follows the System UI Theme Specification and defines all design tokens used throughout the application.
interface Theme {
/** Color palette including mode variants */
colors?: ColorTheme;
/** Font family definitions */
fonts?: { [key: string]: string };
/** Font size scale (array or object) */
fontSizes?: (string | number)[] | { [key: string]: string | number };
/** Font weight definitions */
fontWeights?: { [key: string]: string | number };
/** Line height scale */
lineHeights?: { [key: string]: string | number };
/** Spacing scale for margin and padding */
space?: (string | number)[] | { [key: string]: string | number };
/** Size scale for width, height, etc. */
sizes?: { [key: string]: string | number };
/** Border radius scale */
radii?: { [key: string]: string | number };
/** Box shadow definitions */
shadows?: { [key: string]: string };
/** Responsive breakpoints */
breakpoints?: Breakpoints;
/** Z-index scale */
zIndices?: { [key: string]: number };
/** Global and element styles */
styles?: ThemeStyles;
/** Component variant definitions */
[componentName: string]: any;
}Usage Examples:
const theme = {
// Color system with modes
colors: {
text: '#333',
background: '#fff',
primary: '#007acc',
secondary: '#ff6b6b',
muted: '#f6f6f6',
accent: '#9c27b0',
modes: {
dark: {
text: '#fff',
background: '#111',
primary: '#3eb8ff',
secondary: '#ff8a80',
muted: '#2d2d2d'
}
}
},
// Typography scale
fonts: {
body: '"Inter", system-ui, sans-serif',
heading: '"Playfair Display", Georgia, serif',
monospace: '"Fira Code", Consolas, monospace'
},
fontSizes: [12, 14, 16, 20, 24, 32, 48, 64, 96],
fontWeights: {
light: 300,
normal: 400,
medium: 500,
semibold: 600,
bold: 700,
extrabold: 800
},
lineHeights: {
solid: 1,
title: 1.25,
copy: 1.5,
loose: 1.75
},
// Spacing and sizing
space: [0, 4, 8, 16, 32, 64, 128, 256, 512],
sizes: {
container: 1200,
sidebar: 300,
avatar: 48
},
// Design tokens
radii: {
none: 0,
sm: 2,
default: 4,
md: 6,
lg: 8,
xl: 12,
full: 9999
},
shadows: {
sm: '0 1px 3px rgba(0,0,0,0.12)',
md: '0 4px 6px rgba(0,0,0,0.12)',
lg: '0 10px 25px rgba(0,0,0,0.12)',
inner: 'inset 0 2px 4px rgba(0,0,0,0.06)'
},
// Responsive breakpoints
breakpoints: ['40em', '52em', '64em', '80em']
}Theme UI provides built-in support for multiple color modes with automatic persistence and flash prevention.
interface ColorTheme {
/** Base color definitions */
[colorName: string]: string;
/** Color mode variants */
modes?: {
[modeName: string]: {
[colorName: string]: string;
};
};
}
interface ColorModeOptions {
/** Initial color mode */
initialColorModeName?: string;
/** Use system preference for initial mode */
useColorSchemeMediaQuery?: boolean;
/** Use custom color mode storage */
useLocalStorage?: boolean;
}Usage Examples:
// Color mode configuration in theme
const theme = {
initialColorModeName: 'light',
useColorSchemeMediaQuery: true,
colors: {
text: '#000',
background: '#fff',
primary: '#007acc',
modes: {
dark: {
text: '#fff',
background: '#111',
primary: '#3eb8ff'
},
sepia: {
text: '#5c4e37',
background: '#f4f3e8',
primary: '#8b4513'
}
}
}
}
// Component using color mode
import { useColorMode } from 'theme-ui'
function ColorModeToggle() {
const [colorMode, setColorMode] = useColorMode()
return (
<button
onClick={() => {
const modes = ['light', 'dark', 'sepia']
const next = modes[(modes.indexOf(colorMode) + 1) % modes.length]
setColorMode(next)
}}
>
Switch to {colorMode === 'light' ? 'dark' : 'light'} mode
</button>
)
}Theme UI supports global styles and element styling through the styles object in the theme.
interface ThemeStyles {
/** Root element styles */
root?: ThemeUIStyleObject;
/** HTML element styles by tag name */
[element: string]: ThemeUIStyleObject | undefined;
}
interface GlobalStylesProps {
styles?: ThemeStyles;
}
function Global(props: GlobalStylesProps): JSX.Element;Usage Examples:
// Global styles in theme
const theme = {
styles: {
root: {
fontFamily: 'body',
lineHeight: 'body',
fontWeight: 'body',
color: 'text',
bg: 'background',
margin: 0,
padding: 0,
boxSizing: 'border-box'
},
h1: {
fontFamily: 'heading',
fontWeight: 'bold',
fontSize: 6,
lineHeight: 'title',
color: 'text',
mt: 0,
mb: 3
},
h2: {
fontFamily: 'heading',
fontWeight: 'bold',
fontSize: 5,
lineHeight: 'title',
color: 'text',
mt: 0,
mb: 3
},
p: {
fontFamily: 'body',
fontSize: 2,
lineHeight: 'copy',
color: 'text',
mt: 0,
mb: 3
},
a: {
color: 'primary',
textDecoration: 'none',
'&:hover': {
textDecoration: 'underline'
}
}
}
}
// Manual global styles injection
import { Global } from 'theme-ui'
function App() {
return (
<>
<Global
styles={{
'*': {
boxSizing: 'border-box'
},
body: {
margin: 0,
fontFamily: 'system-ui'
}
}}
/>
<main>App content</main>
</>
)
}Theme UI supports component variants for consistent styling patterns across your design system.
interface ComponentVariants {
[componentName: string]: {
[variantName: string]: ThemeUIStyleObject;
};
}
interface VariantProps {
/** Component variant name */
variant?: string;
}Usage Examples:
// Component variants in theme
const theme = {
buttons: {
primary: {
bg: 'primary',
color: 'white',
border: 'none',
borderRadius: 'default',
px: 4,
py: 2,
fontSize: 2,
fontWeight: 'semibold',
cursor: 'pointer',
'&:hover': {
bg: 'secondary'
}
},
secondary: {
bg: 'transparent',
color: 'primary',
border: '2px solid',
borderColor: 'primary',
borderRadius: 'default',
px: 4,
py: 2,
fontSize: 2,
fontWeight: 'semibold',
cursor: 'pointer',
'&:hover': {
bg: 'primary',
color: 'white'
}
},
ghost: {
bg: 'transparent',
color: 'text',
border: 'none',
px: 4,
py: 2,
fontSize: 2,
fontWeight: 'normal',
cursor: 'pointer',
'&:hover': {
bg: 'muted'
}
}
},
cards: {
primary: {
bg: 'background',
border: '1px solid',
borderColor: 'muted',
borderRadius: 'default',
p: 4,
boxShadow: 'sm'
},
elevated: {
bg: 'background',
border: 'none',
borderRadius: 'lg',
p: 4,
boxShadow: 'lg'
}
},
text: {
heading: {
fontFamily: 'heading',
fontWeight: 'bold',
lineHeight: 'title',
color: 'text'
},
body: {
fontFamily: 'body',
fontWeight: 'normal',
lineHeight: 'copy',
color: 'text'
},
caption: {
fontFamily: 'body',
fontSize: 1,
fontWeight: 'normal',
lineHeight: 'copy',
color: 'muted'
}
}
}
// Using variants in components
import { Button, Card, Text } from 'theme-ui'
function Example() {
return (
<Card variant="elevated">
<Text variant="heading" as="h2">
Card Title
</Text>
<Text variant="body">
Card content goes here.
</Text>
<Button variant="primary">
Primary Action
</Button>
<Button variant="secondary" sx={{ ml: 2 }}>
Secondary Action
</Button>
</Card>
)
}The BaseStyles component applies base theme styles to its children, useful for styling content from external sources.
interface BaseStylesProps extends SxProp {
/** Child content to apply base styles to */
children?: React.ReactNode;
[key: string]: any;
}
function BaseStyles(props: BaseStylesProps): JSX.Element;Usage Examples:
import { BaseStyles } from 'theme-ui'
// Apply theme styles to markdown content
function MarkdownContent({ html }) {
return (
<BaseStyles>
<div dangerouslySetInnerHTML={{ __html: html }} />
</BaseStyles>
)
}
// Wrap external content
function ExternalContent({ children }) {
return (
<BaseStyles sx={{
'& h1': { fontSize: 5 },
'& p': { mb: 3 }
}}>
{children}
</BaseStyles>
)
}Theme UI includes utilities to prevent flash of unstyled content (FOUC) during color mode transitions.
/**
* Script component to prevent color mode flash during SSR hydration
*/
function InitializeColorMode(): JSX.Element;Usage Examples:
// In your app's document head (Next.js _document.js)
import { InitializeColorMode } from 'theme-ui'
export default function Document() {
return (
<Html>
<Head />
<body>
<InitializeColorMode />
<Main />
<NextScript />
</body>
</Html>
)
}
// In Gatsby (handled automatically by gatsby-plugin-theme-ui)
// No manual setup requiredinterface Theme {
colors?: ColorTheme;
fonts?: { [key: string]: string };
fontSizes?: (string | number)[] | { [key: string]: string | number };
fontWeights?: { [key: string]: string | number };
lineHeights?: { [key: string]: string | number };
space?: (string | number)[] | { [key: string]: string | number };
sizes?: { [key: string]: string | number };
radii?: { [key: string]: string | number };
shadows?: { [key: string]: string };
breakpoints?: Breakpoints;
zIndices?: { [key: string]: number };
styles?: ThemeStyles;
[componentName: string]: any;
}
interface ColorTheme {
[colorName: string]: string;
modes?: {
[modeName: string]: {
[colorName: string]: string;
};
};
}
interface ThemeStyles {
root?: ThemeUIStyleObject;
[element: string]: ThemeUIStyleObject | undefined;
}
interface ThemeUIStyleObject {
[property: string]: ResponsiveStyleValue<any>;
}
type ResponsiveStyleValue<T> = T | Array<T | null | undefined>;
interface Breakpoints extends Array<string> {
[key: string]: string;
}
interface ThemeUIProviderProps {
theme: Theme;
children: React.ReactNode;
}
interface ColorModeOptions {
initialColorModeName?: string;
useColorSchemeMediaQuery?: boolean;
useLocalStorage?: boolean;
}
interface VariantProps {
variant?: string;
}
interface BaseStylesProps extends SxProp {
children?: React.ReactNode;
[key: string]: any;
}
interface ComponentVariants {
[componentName: string]: {
[variantName: string]: ThemeUIStyleObject;
};
}