Core
Theme Schema (ThemeSchema)
Dynamic theming with light/dark modes, color palettes, and typography
Theme Schema
The ThemeSchema provides a comprehensive theming system for ObjectUI applications, supporting light/dark modes, custom color palettes, typography, and CSS variable integration.
Overview
ThemeSchema enables:
- Multiple theme definitions - Create and switch between custom themes
- Light/Dark modes - Automatic mode switching with persistence
- Color palettes - 20+ semantic colors for consistent design
- Typography system - Font families, sizes, weights, and line heights
- Tailwind integration - Direct integration with Tailwind CSS
- CSS variables - Custom CSS variable support
Interactive Examples
Color Palette Preview
Semantic Color Palette
Preview of semantic color tokens used across the theme system
{
"type": "grid",
"cols": 4,
"gap": 3,
"className": "p-4",
"children": [
{
"type": "card",
"className": "p-4 text-center",
"children": [
{
"type": "div",
"className": "w-full h-12 rounded-md bg-primary mb-2"
},
{
"type": "text",
"content": "Primary",
"className": "text-xs font-medium"
}
]
},
{
"type": "card",
"className": "p-4 text-center",
"children": [
{
"type": "div",
"className": "w-full h-12 rounded-md bg-secondary mb-2"
},
{
"type": "text",
"content": "Secondary",
"className": "text-xs font-medium"
}
]
},
{
"type": "card",
"className": "p-4 text-center",
"children": [
{
"type": "div",
"className": "w-full h-12 rounded-md bg-accent mb-2"
},
{
"type": "text",
"content": "Accent",
"className": "text-xs font-medium"
}
]
},
{
"type": "card",
"className": "p-4 text-center",
"children": [
{
"type": "div",
"className": "w-full h-12 rounded-md bg-muted mb-2"
},
{
"type": "text",
"content": "Muted",
"className": "text-xs font-medium"
}
]
},
{
"type": "card",
"className": "p-4 text-center",
"children": [
{
"type": "div",
"className": "w-full h-12 rounded-md bg-destructive mb-2"
},
{
"type": "text",
"content": "Destructive",
"className": "text-xs font-medium"
}
]
},
{
"type": "card",
"className": "p-4 text-center",
"children": [
{
"type": "div",
"className": "w-full h-12 rounded-md bg-card border mb-2"
},
{
"type": "text",
"content": "Card",
"className": "text-xs font-medium"
}
]
},
{
"type": "card",
"className": "p-4 text-center",
"children": [
{
"type": "div",
"className": "w-full h-12 rounded-md bg-popover border mb-2"
},
{
"type": "text",
"content": "Popover",
"className": "text-xs font-medium"
}
]
},
{
"type": "card",
"className": "p-4 text-center",
"children": [
{
"type": "div",
"className": "w-full h-12 rounded-md border-2 border-border mb-2"
},
{
"type": "text",
"content": "Border",
"className": "text-xs font-medium"
}
]
}
]
}Theme-Aware Components
Theme-Aware UI Elements
Components automatically adapt to the active theme's color palette
{
"type": "stack",
"spacing": 4,
"children": [
{
"type": "flex",
"className": "gap-2 flex-wrap",
"children": [
{
"type": "button",
"label": "Primary",
"variant": "default"
},
{
"type": "button",
"label": "Secondary",
"variant": "secondary"
},
{
"type": "button",
"label": "Outline",
"variant": "outline"
},
{
"type": "button",
"label": "Ghost",
"variant": "ghost"
},
{
"type": "button",
"label": "Destructive",
"variant": "destructive"
}
]
},
{
"type": "flex",
"className": "gap-2 flex-wrap",
"children": [
{
"type": "badge",
"label": "Default",
"variant": "default"
},
{
"type": "badge",
"label": "Secondary",
"variant": "secondary"
},
{
"type": "badge",
"label": "Outline",
"variant": "outline"
},
{
"type": "badge",
"label": "Destructive",
"variant": "destructive"
}
]
},
{
"type": "grid",
"cols": 2,
"gap": 3,
"children": [
{
"type": "card",
"header": [
{
"type": "text",
"content": "Card Title",
"className": "font-semibold"
}
],
"children": [
{
"type": "text",
"content": "This card uses theme-aware background and foreground colors.",
"className": "text-sm text-muted-foreground"
}
]
},
{
"type": "card",
"className": "bg-muted",
"header": [
{
"type": "text",
"content": "Muted Card",
"className": "font-semibold"
}
],
"children": [
{
"type": "text",
"content": "A muted-background variant for subtle content areas.",
"className": "text-sm text-muted-foreground"
}
]
}
]
}
]
}Basic Usage
import type { ThemeSchema } from '@object-ui/types';
const theme: ThemeSchema = {
type: 'theme',
mode: 'dark',
themes: [
{
name: 'professional',
label: 'Professional',
light: {
primary: '#3b82f6',
background: '#ffffff',
foreground: '#0f172a'
},
dark: {
primary: '#60a5fa',
background: '#0f172a',
foreground: '#f1f5f9'
}
}
],
activeTheme: 'professional',
allowSwitching: true,
persistPreference: true
};Properties
Theme Configuration
| Property | Type | Default | Description |
|---|---|---|---|
type | 'theme' | - | Component type identifier (required) |
mode | 'light' | 'dark' | 'system' | 'light' | Current theme mode |
themes | ThemeDefinition[] | - | Available theme definitions |
activeTheme | string | - | Currently active theme name |
allowSwitching | boolean | false | Allow users to switch themes |
persistPreference | boolean | false | Save theme preference to localStorage |
storageKey | string | 'theme' | Storage key for persisting theme |
Theme Definition
interface ThemeDefinition {
name: string; // Theme identifier
label?: string; // Display name
light?: ColorPalette; // Light mode colors
dark?: ColorPalette; // Dark mode colors
typography?: Typography;
spacing?: SpacingScale;
radius?: BorderRadius;
cssVariables?: Record<string, string>;
tailwind?: Record<string, any>;
}Color Palette
Semantic color tokens for consistent design:
interface ColorPalette {
// Brand colors
primary?: string;
secondary?: string;
accent?: string;
// Base colors
background?: string;
foreground?: string;
muted?: string;
mutedForeground?: string;
// Component colors
card?: string;
cardForeground?: string;
popover?: string;
popoverForeground?: string;
// UI elements
border?: string;
input?: string;
ring?: string;
// Status colors
success?: string;
warning?: string;
destructive?: string;
info?: string;
}Example Color Palette
{
"light": {
"primary": "#3b82f6",
"secondary": "#64748b",
"accent": "#8b5cf6",
"background": "#ffffff",
"foreground": "#0f172a",
"muted": "#f1f5f9",
"mutedForeground": "#64748b",
"border": "#e2e8f0",
"input": "#e2e8f0",
"ring": "#3b82f6",
"success": "#10b981",
"warning": "#f59e0b",
"destructive": "#ef4444",
"info": "#3b82f6"
},
"dark": {
"primary": "#60a5fa",
"secondary": "#94a3b8",
"accent": "#a78bfa",
"background": "#0f172a",
"foreground": "#f1f5f9",
"muted": "#1e293b",
"mutedForeground": "#94a3b8",
"border": "#334155",
"input": "#334155",
"ring": "#60a5fa",
"success": "#34d399",
"warning": "#fbbf24",
"destructive": "#f87171",
"info": "#60a5fa"
}
}Typography System
interface Typography {
fontSans?: string[]; // Sans-serif font stack
fontSerif?: string[]; // Serif font stack
fontMono?: string[]; // Monospace font stack
fontSize?: number; // Base font size (rem)
lineHeight?: number; // Base line height
headingWeight?: number; // Font weight for headings
bodyWeight?: number; // Font weight for body text
}Example Typography
{
"typography": {
"fontSans": ["Inter", "system-ui", "sans-serif"],
"fontSerif": ["Merriweather", "Georgia", "serif"],
"fontMono": ["JetBrains Mono", "monospace"],
"fontSize": 16,
"lineHeight": 1.5,
"headingWeight": 600,
"bodyWeight": 400
}
}Spacing Scale
interface SpacingScale {
base?: number; // Base spacing unit (rem)
scale?: Record<string, string>; // Custom spacing values
}Border Radius
interface BorderRadius {
sm?: string;
default?: string;
md?: string;
lg?: string;
xl?: string;
}Complete Theme Example
const professionalTheme: ThemeSchema = {
type: 'theme',
mode: 'system',
themes: [
{
name: 'professional',
label: 'Professional',
light: {
primary: '#3b82f6',
secondary: '#64748b',
accent: '#8b5cf6',
background: '#ffffff',
foreground: '#0f172a',
muted: '#f1f5f9',
mutedForeground: '#64748b',
card: '#ffffff',
cardForeground: '#0f172a',
popover: '#ffffff',
popoverForeground: '#0f172a',
border: '#e2e8f0',
input: '#e2e8f0',
ring: '#3b82f6',
success: '#10b981',
warning: '#f59e0b',
destructive: '#ef4444',
info: '#3b82f6'
},
dark: {
primary: '#60a5fa',
secondary: '#94a3b8',
accent: '#a78bfa',
background: '#0f172a',
foreground: '#f1f5f9',
muted: '#1e293b',
mutedForeground: '#94a3b8',
card: '#1e293b',
cardForeground: '#f1f5f9',
popover: '#1e293b',
popoverForeground: '#f1f5f9',
border: '#334155',
input: '#334155',
ring: '#60a5fa',
success: '#34d399',
warning: '#fbbf24',
destructive: '#f87171',
info: '#60a5fa'
},
typography: {
fontSans: ['Inter', 'system-ui', 'sans-serif'],
fontSize: 16,
lineHeight: 1.5,
headingWeight: 600,
bodyWeight: 400
},
spacing: {
base: 0.25,
scale: {
'0': '0',
'1': '0.25rem',
'2': '0.5rem',
'4': '1rem',
'8': '2rem'
}
},
radius: {
sm: '0.25rem',
default: '0.5rem',
md: '0.75rem',
lg: '1rem',
xl: '1.5rem'
},
cssVariables: {
'--header-height': '4rem',
'--sidebar-width': '16rem'
}
}
],
activeTheme: 'professional',
allowSwitching: true,
persistPreference: true,
storageKey: 'app-theme'
};Theme Switcher
Use ThemeSwitcherSchema to add a theme switcher UI:
import type { ThemeSwitcherSchema } from '@object-ui/types';
const switcher: ThemeSwitcherSchema = {
type: 'theme-switcher',
variant: 'dropdown',
showMode: true, // Show light/dark mode toggle
showThemes: true, // Show theme selector
lightIcon: 'Sun',
darkIcon: 'Moon'
};Switcher Variants
dropdown- Dropdown menu with theme optionstoggle- Simple light/dark toggle buttonbuttons- Button group with all options
Theme Preview
Use ThemePreviewSchema to preview themes:
import type { ThemePreviewSchema } from '@object-ui/types';
const preview: ThemePreviewSchema = {
type: 'theme-preview',
theme: professionalTheme.themes[0],
mode: 'light',
showColors: true,
showTypography: true,
showComponents: true
};Runtime Validation
import { ThemeSchema } from '@object-ui/types/zod';
const result = ThemeSchema.safeParse(myTheme);
if (result.success) {
console.log('Valid theme configuration');
} else {
console.error('Validation errors:', result.error);
}Use Cases
ThemeSchema is perfect for:
- Brand consistency - Maintain consistent visual identity across applications
- White-labeling - Enable multi-tenant applications with custom branding
- Accessibility - Provide light/dark modes for user preference
- Design systems - Implement comprehensive design tokens
- A/B testing - Test different color schemes and typography
Best Practices
- Use semantic colors - Stick to the semantic color tokens for consistency
- Test both modes - Always test light and dark modes
- Maintain contrast - Ensure sufficient color contrast for accessibility
- Limit custom themes - Offer 2-3 well-designed themes max
- Respect system preferences - Use
mode: 'system'by default - Persist preferences - Enable
persistPreferencefor better UX
Related
- App Schema - Application configuration
- CSS Variables - MDN documentation
- Tailwind Theming - Tailwind CSS theming guide