Theming
Theme presets, dark mode, and how to create custom themes. uicraft supports multiple visual themes and light/dark mode independently.
How It Works
Two independent axes: visual theme (fonts, radius, colors) and color mode (light/dark).
Visual Theme
data-theme="..."
Controls font family, border radius, color palette
Color Mode
class="dark"
Toggles light/dark semantic tokens
Built-in Presets
Three theme presets ship with uicraft. Each changes fonts, radius, and subtle color shifts.
| Theme | Font Family | Radius (lg) | Character |
|---|---|---|---|
| default | Inter, system-ui, sans-serif | 12px | Clean and modern |
| editorial | Source Serif 4, Georgia, serif | 10px | Classic, editorial feel |
| rounded-sans | Manrope, Inter, sans-serif | 14px | Soft, rounded corners |
Aa
Default
data-theme="default"
Aa
Editorial
data-theme="editorial"
Aa
Rounded Sans
data-theme="rounded-sans"
Dark Mode
Add .dark to <html> to switch all semantic tokens to their dark variants.
Light mode
--fg-primary → grey-950
--neutrals-background → grey-50
--neutrals-surface → white
--border-default → grey-100
Dark mode
--fg-primary → grey-50
--neutrals-background → grey-950
--neutrals-surface → black
--border-default → grey-900
html
Dark mode toggle & persistence script
<!-- Toggle dark mode with JS -->
<script>
function toggleDarkMode() {
const html = document.documentElement;
html.classList.toggle('dark');
const mode = html.classList.contains('dark') ? 'dark' : 'light';
localStorage.setItem('theme', mode);
}
</script>
<!-- Restore on page load (put in <head>) -->
<script>
const mode = localStorage.getItem('theme');
if (mode === 'dark' ||
(!mode && matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark');
}
</script>
Switching Themes
Set data-theme on <html> and persist with localStorage.
html
Live Theme Controls
Mode
Theme
Live Tokens
Preview
Foreground and accents react to current theme + mode.
Semantic tokens in syncSample Component
Button
Radius and colors update as you switch presets.
<!-- Switch theme preset -->
<script>
function setTheme(name) {
document.documentElement.setAttribute('data-theme', name);
localStorage.setItem('uicraft-theme', name);
}
// Restore on page load
const theme = localStorage.getItem('uicraft-theme') || 'default';
document.documentElement.setAttribute('data-theme', theme);
</script>
Token Override Order
How CSS specificity works: theme preset → dark mode → component styles → utilities.
1
Theme preset — sets font, radius, base color tokens
2
Dark mode — overrides color tokens for dark palette
3
Component classes — uc-btn, uc-card use tokens
4
Utility classes — override anything inline
Custom Theme
Create a JSON file in themes/ to add your own preset.
json
1
Create a JSON file:
themes/my-theme.json2
Run the build — theme CSS is auto-generated from JSON
3
Apply with
data-theme="my-theme"{
"name": "my-theme",
"label": "My Theme",
"fontFamily": "Poppins, system-ui, sans-serif",
"radius": {
"sm": "8px",
"lg": "12px",
"xl": "16px",
"2xl": "20px",
"3xl": "24px"
},
"colors": {
"constantWhite": "0 0% 100%",
"constantBlack": "0 0% 0%",
"fgPrimary": "240 3% 6%",
"fgSecondary": "228 4% 25%",
"fgTertiary": "227 4% 43%",
"fgDisabled": "231 6% 61%",
"neutralsBackground": "0 0% 98%",
"neutralsSurface": "0 0% 100%",
"neutralsSubtle": "0 0% 98%",
"neutralsMuted": "0 0% 96%",
"neutralsEmphasis": "0 5% 92%",
"borderDefault": "0 5% 92%",
"borderStrong": "245 10% 78%",
"accentsBlue": "219 88% 54%",
"accentsGreen": "162 86% 40%",
"accentsRed": "4 83% 55%",
"accentsOrange": "30 100% 55%",
"tintRed": "0 100% 95%",
"tintGreen": "152 39% 89%",
"tintBlue": "217 100% 92%",
"tintOrange": "34 100% 95%"
},
"dark": {
"colors": {
"fgPrimary": "0 0% 98%",
...
}
}
}