← All Guidelines
Canon
Theming
Canon's token architecture enables systematic theming. Override tokens at the root level to create consistent custom themes.
Published January 8, 2026
Philosophy
Themes should extend, not replace. Canon provides a complete token system that establishes relationships between colors, spacing, and typography. Custom themes override specific tokens while maintaining these relationships.
“A system is not the sum of its parts but the product of their interactions.” — Russell Ackoff
Token Categories
These tokens form the theming surface. Override them to create custom themes.
Background Tokens
--color-bg-pure--color-bg-base--color-bg-surface--color-bg-elevated
Foreground Tokens
--color-fg-primary--color-fg-secondary--color-fg-tertiary--color-fg-muted
Border Tokens
--color-border-default--color-border-emphasis--color-border-strong
Semantic Tokens
--color-success--color-error--color-warning--color-info
Creating a Custom Theme
Override Canon’s tokens at the root level:
:root {
/* Brand color as accent */
--color-accent: #6366f1;
--color-accent-muted: rgba(99, 102, 241, 0.1);
/* Custom backgrounds */
--color-bg-pure: #0f0f23;
--color-bg-base: #1a1a2e;
--color-bg-surface: #252538;
--color-bg-elevated: #2f2f45;
} Dark & Light Modes
Canon defaults to dark mode. Add light mode with a theme attribute:
/* Dark mode (default) */
:root {
--color-bg-pure: #000000;
--color-bg-base: #0a0a0a;
--color-fg-primary: rgba(255, 255, 255, 1);
--color-fg-secondary: rgba(255, 255, 255, 0.8);
}
/* Light mode override */
[data-theme="light"] {
--color-bg-pure: #ffffff;
--color-bg-base: #fafafa;
--color-fg-primary: rgba(0, 0, 0, 0.9);
--color-fg-secondary: rgba(0, 0, 0, 0.7);
} Theme Toggle
<button onclick="toggleTheme()">Toggle Theme</button>
<script>
function toggleTheme() {
const current = document.documentElement.dataset.theme;
document.documentElement.dataset.theme =
current === 'light' ? 'dark' : 'light';
}
</script> System Preference Detection
Respect user’s system preference:
@media (prefers-color-scheme: light) {
:root:not([data-theme="dark"]) {
--color-bg-pure: #ffffff;
--color-bg-base: #fafafa;
/* ... light mode tokens ... */
}
} Theme Best Practices
- Override, don’t replace - Maintain token relationships
- Test contrast - Ensure AA compliance in all themes
- Preserve semantics - Success should still feel “green”
- Respect preferences - Honor
prefers-color-scheme - Provide toggle - Let users choose their preference
Complete Light Theme Example
[data-theme="light"] {
/* Backgrounds - inverted */
--color-bg-pure: #ffffff;
--color-bg-base: #fafafa;
--color-bg-surface: #f5f5f5;
--color-bg-elevated: #ffffff;
/* Foregrounds - dark text */
--color-fg-primary: rgba(0, 0, 0, 0.9);
--color-fg-secondary: rgba(0, 0, 0, 0.7);
--color-fg-tertiary: rgba(0, 0, 0, 0.5);
--color-fg-muted: rgba(0, 0, 0, 0.4);
/* Borders - adjusted for light bg */
--color-border-default: rgba(0, 0, 0, 0.1);
--color-border-emphasis: rgba(0, 0, 0, 0.2);
--color-border-strong: rgba(0, 0, 0, 0.3);
/* Interactive - adjusted */
--color-hover: rgba(0, 0, 0, 0.05);
--color-active: rgba(0, 0, 0, 0.1);
}