Theming
Theming
Theming
Create custom themes for your application using PrimitiveKit’s design token system.
Overview
PrimitiveKit uses CSS variables (custom properties) for theming, making it easy to create light/dark themes or completely custom color schemes.
Quick Start
Basic Theme
:root {
/* Primary colors */
--color-primary: #007bff;
--color-primary-hover: #0056b3;
--color-primary-active: #004085;
/* Text colors */
--color-text: #212529;
--color-text-secondary: #6c757d;
/* Background colors */
--color-bg: #ffffff;
--color-bg-secondary: #f8f9fa;
}Dark Mode
Automatic Dark Mode
:root {
--color-bg: #ffffff;
--color-text: #212529;
}
@media (prefers-color-scheme: dark) {
:root {
--color-bg: #212529;
--color-text: #ffffff;
}
}Manual Dark Mode Toggle
/* Light theme (default) */
:root {
--color-bg: #ffffff;
--color-text: #212529;
}
/* Dark theme */
[data-theme="dark"] {
--color-bg: #212529;
--color-text: #ffffff;
}// Toggle dark mode
function ThemeToggle() {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
const newTheme = theme === 'light' ? 'dark' : 'light';
setTheme(newTheme);
document.documentElement.setAttribute('data-theme', newTheme);
};
return (
<Button onClick={toggleTheme}>
Toggle {theme === 'light' ? 'Dark' : 'Light'} Mode
</Button>
);
}Custom Themes
Brand Theme
:root {
/* Brand colors */
--color-primary: #ff6b6b;
--color-secondary: #4ecdc4;
--color-accent: #ffe66d;
/* Typography */
--font-family: 'Inter', sans-serif;
--font-size-base: 16px;
/* Spacing */
--spacing-unit: 8px;
/* Border radius */
--border-radius-sm: 4px;
--border-radius-md: 8px;
--border-radius-lg: 16px;
}Multiple Themes
/* Default theme */
:root {
--color-primary: #007bff;
}
/* Ocean theme */
[data-theme="ocean"] {
--color-primary: #0077be;
--color-secondary: #00a8e8;
--color-accent: #00c9ff;
}
/* Forest theme */
[data-theme="forest"] {
--color-primary: #2d6a4f;
--color-secondary: #40916c;
--color-accent: #52b788;
}
/* Sunset theme */
[data-theme="sunset"] {
--color-primary: #ff6b6b;
--color-secondary: #ee5a6f;
--color-accent: #f4a261;
}Component-Specific Theming
Button Theme
:root {
/* Button colors */
--button-primary-bg: #007bff;
--button-primary-color: #ffffff;
--button-primary-hover-bg: #0056b3;
/* Button sizes */
--button-padding-sm: 4px 12px;
--button-padding-md: 8px 16px;
--button-padding-lg: 12px 24px;
/* Button borders */
--button-border-radius: 8px;
--button-border-width: 1px;
}Input Theme
:root {
/* Input colors */
--input-bg: #ffffff;
--input-border: #ced4da;
--input-focus-border: #007bff;
--input-text: #212529;
/* Input sizes */
--input-padding: 8px 12px;
--input-height: 40px;
/* Input borders */
--input-border-radius: 4px;
--input-border-width: 1px;
}Theme Presets
Minimal Theme
:root {
--color-primary: #000000;
--color-secondary: #666666;
--color-bg: #ffffff;
--color-text: #000000;
--border-radius-sm: 0px;
--border-radius-md: 0px;
--border-radius-lg: 0px;
--font-family: 'Helvetica Neue', sans-serif;
}Playful Theme
:root {
--color-primary: #ff6b6b;
--color-secondary: #4ecdc4;
--color-accent: #ffe66d;
--border-radius-sm: 12px;
--border-radius-md: 16px;
--border-radius-lg: 24px;
--font-family: 'Comic Sans MS', cursive;
}Professional Theme
:root {
--color-primary: #2c3e50;
--color-secondary: #34495e;
--color-accent: #3498db;
--color-bg: #ecf0f1;
--color-text: #2c3e50;
--border-radius-sm: 2px;
--border-radius-md: 4px;
--border-radius-lg: 6px;
--font-family: 'Roboto', sans-serif;
}Dynamic Theming
React Context
import { createContext, useContext, useState } from 'react';
const ThemeContext = createContext();
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const applyTheme = (themeName) => {
setTheme(themeName);
document.documentElement.setAttribute('data-theme', themeName);
};
return (
<ThemeContext.Provider value={{ theme, applyTheme }}>
{children}
</ThemeContext.Provider>
);
}
export function useTheme() {
return useContext(ThemeContext);
}Usage
function App() {
const { theme, applyTheme } = useTheme();
return (
<div>
<select
value={theme}
onChange={(e) => applyTheme(e.target.value)}
>
<option value="light">Light</option>
<option value="dark">Dark</option>
<option value="ocean">Ocean</option>
<option value="forest">Forest</option>
</select>
</div>
);
}Best Practices
1. Use Semantic Names
/* ✅ Good */
--color-primary
--color-text
--color-bg
/* ❌ Avoid */
--blue
--dark-gray
--white2. Maintain Contrast
Ensure sufficient color contrast for accessibility:
/* ✅ Good - 4.5:1 contrast ratio */
--color-text: #212529;
--color-bg: #ffffff;
/* ❌ Poor - Low contrast */
--color-text: #cccccc;
--color-bg: #ffffff;3. Test Both Themes
Always test your application in both light and dark modes.
4. Use CSS Variables Consistently
/* ✅ Good */
.button {
background: var(--button-primary-bg);
color: var(--button-primary-color);
}
/* ❌ Avoid hardcoded values */
.button {
background: #007bff;
color: #ffffff;
}Resources
- Design Tokens - Complete token reference
- Customization - Customization guide
- Accessibility - Accessibility guidelines
Examples
Check out our Showcase for real-world theming examples.