Theme Generator
Gentelella ships a live theme generator at production/theme.html. Pick a primary color, sidebar style, radius, or font size — watch every chart, button, and badge restyle in real time. Copy or download the resulting :root block straight into _tokens.scss.
Last updated May 22, 2026
The theme generator is one of Gentelella’s headline features. It’s a regular page in production/theme.html — not a separate app — that lets you preview design-token overrides live, then ship them back to _tokens.scss with a copy-paste.
How it works
The page exposes four control surfaces:
- Primary color — 11 preset swatches (the original Gentelella teal plus 10 alternatives) and a custom HTML5 color picker
- Sidebar style — dark navy (default), light, or brand-colored (uses the primary as the background)
- Radius — slider from 0px to 16px, controls
--radius,--radius-sm,--radius-lg - Sidebar width — slider from 200px to 320px
- Font size — slider from 12px to 16px
Below the controls, an instance of every major component renders so you can see the live impact: buttons, badges, alerts, cards, form controls, tables, charts. A “Tokens” panel on the right shows the generated :root block in real time.
The mechanism — <style id="theme-overrides">
Instead of editing the actual _tokens.scss rules in memory, the generator writes a new <style id="theme-overrides"> tag in <head> with higher specificity. The original tokens stay intact; the override layer wins by being later in the cascade.
Simplified version of the generator’s apply function:
const styleTag = document.createElement('style');
styleTag.id = 'theme-overrides';
document.head.appendChild(styleTag);
function applyOverrides(state) {
styleTag.textContent = `
:root {
--primary: ${state.primary};
--primary-dk: ${state.primaryDk};
--primary-lt: ${hexToRgba(state.primary, 0.10)};
--radius: ${state.radius}px;
--radius-sm: ${Math.max(0, state.radius - 2)}px;
--radius-lg: ${state.radius + 2}px;
--sidebar-w: ${state.sidebarW}px;
--font-size: ${state.fontSize / 16}rem;
}
`;
// Notify charts so they re-render with the new tokens.
document.documentElement.dispatchEvent(new CustomEvent('themechange'));
}
The themechange event is what triggers ECharts to rebuild — see ECharts for how the chart factories listen for it.
Persistence
Overrides are stored in sessionStorage, not localStorage. This is intentional:
- The theme generator is a try-before-you-commit tool
- You don’t want overrides from
production/theme.htmlto leak into the rest of the template on subsequent visits toindex.html - The session-scope lets you tweak, navigate away, come back, and pick up where you left off without polluting other pages
If you want a permanent change, copy the generated :root block from the Tokens panel and paste it into src/scss/v4/_tokens.scss. That’s the only way the overrides become global.
The preset swatches
The 11 default colors with their dark variants:
| Color | Primary | Primary dark |
|---|---|---|
| Teal (default) | #1ABB9C | #169f85 |
| Blue | #066fd1 | #054ea0 |
| Indigo | #4263eb | #2747c4 |
| Purple | #ae3ec9 | #8628a0 |
| Pink | #d6336c | #a82054 |
| Red | #d63939 | #a82b2b |
| Orange | #f76707 | #c25204 |
| Yellow | #f59f00 | #c27d00 |
| Green | #2fb344 | #1f8a30 |
| Cyan | #17a2b8 | #107a8a |
| Black | #0f1623 | #000 |
Each swatch is a <button> with data-primary and data-primary-dk attributes. The click handler reads those and updates the state object before re-rendering the override style tag.
To add your own preset, edit production/theme.html and append a <button> to #primary-swatches:
<button type="button" class="theme-swatch"
data-primary="#3b82f6" data-primary-dk="#1d4ed8"
style="background:#3b82f6"
title="Tailwind blue">
</button>
The custom color picker
For colors outside the presets, the page also exposes a <input type="color"> element. Picking a color fires the standard input event, which the generator handles by deriving the dark variant automatically:
function shadeHex(hex, percent) {
// Mix toward black by `percent` (0.0–1.0) for the -dk variant
const m = hex.replace('#', '').match(/^([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i);
const r = parseInt(m[1], 16) * (1 - percent);
// ...same for g and b
return `#${[r, g, b].map((n) => Math.round(n).toString(16).padStart(2, '0')).join('')}`;
}
This is approximate. For a designer-grade primary/dark pairing you’ll probably tweak the dark value by hand after copying the tokens out.
Sidebar style options
Three modes selectable via radio buttons:
Dark navy (#1a2332 — the default):
--sidebar-bg: #1a2332;
Light sidebar (#ffffff):
--sidebar-bg: #ffffff;
--sidebar-text: var(--text-secondary);
--sidebar-text-active: var(--primary);
--sidebar-text-hover: var(--text);
--sidebar-hover: var(--bg-surface-secondary);
--sidebar-active: var(--primary-lt);
--sidebar-border: var(--border-color-light);
Brand-colored sidebar (uses your chosen primary):
--sidebar-bg: var(--primary);
--sidebar-active: rgba(255,255,255,0.18);
--sidebar-text: rgba(255,255,255,0.7);
--sidebar-text-active: #fff;
--sidebar-text-hover: #fff;
--sidebar-hover: rgba(255,255,255,0.10);
--sidebar-border: rgba(255,255,255,0.18);
These are the exact blocks the generator emits — copy them straight into _tokens.scss for a permanent change.
Download as SCSS partial
Clicking “Download tokens” produces a .scss file with the same content as the Tokens panel, plus a header comment indicating it was generated. Drop it into src/scss/v4/ and @use it from main.scss if you want to keep overrides as a separate partial instead of editing _tokens.scss directly.
Why this isn’t a runtime feature
The override tag works because CSS custom properties cascade and update synchronously. But the generator is only on production/theme.html — it’s not exposed elsewhere in the template. That’s intentional:
- Runtime theme switching is a different problem (it’s what the moon-icon dark/light toggle does — see Theming)
- A user-facing color picker would imply persistence across pages, which means either localStorage (which competes with the user’s preferences) or backend storage (out of scope for a free template)
- The generator’s job is to help you design — not to let your users repaint your dashboard at runtime
If you want a true user-facing color customization feature in your app, fork the generator’s pattern: write a <style> element with overridden tokens, persist state to localStorage instead of sessionStorage, and load the saved values in the page’s <head> before the body renders.
See also
- Theming — the token system the generator is a UI over
- ECharts — how charts pick up theme changes
- Component playground — the other on-page tool for visualizing the design system