G Gentelella v4.0.0

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.

Try the live demo →

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.html to leak into the rest of the template on subsequent visits to index.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:

ColorPrimaryPrimary 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.

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