Skip to content
EliteChart

Change the theme at runtime

Toggle dark/light, push a brand palette, or patch single tokens — all from your own button.

Three ways to update the theme from your own code, in order of permanence: full theme swap, partial token patch, store-level override.

Quick example

code
'use client';
import { useThemeStore, useChartHandle } from '@elitechart/elitechart';
import { darkTheme, lightTheme } from '@elitechart/themes';

export function ThemeButton() {
  const handle = useChartHandle();
  const mode = useThemeStore((s) => s.mode);

  return (
    <button
      onClick={() => {
        handle?.setTheme(mode === 'dark' ? lightTheme : darkTheme);
      }}
    >
      Toggle theme
    </button>
  );
}

How it works

handle.setTheme(theme) swaps the entire theme record; this is what the top-bar moon/sun toggle calls under the hood. Persists the new mode to localStorage.

handle.patchTheme({ ... }) overlays just the keys you specify on top of the active theme. Resets on reload.

useThemeStore.setOverride(key, value) writes a single override into persisted state — survives reload, applied on every theme swap.

Variations

Brand palette (one button)

code
function BrandButton({ handle }: { handle: ChartHandle | null }) {
  return (
    <button
      onClick={() => handle?.patchTheme({
        bgCanvas: '#0f172a',
        seriesUp: '#22d3ee',
        seriesDown: '#f43f5e',
      })}
    >
      Apply brand
    </button>
  );
}

React to system color-scheme changes

code
useEffect(() => {
  const m = matchMedia('(prefers-color-scheme: dark)');
  const onChange = () => handle?.setTheme(m.matches ? darkTheme : lightTheme);
  m.addEventListener('change', onChange);
  return () => m.removeEventListener('change', onChange);
}, [handle]);

API

MethodFromPersistence
handle.setTheme(theme)@elitechart/elitechartsets mode
handle.patchTheme(patch)session only
useThemeStore.setOverride(k, v)persisted
useThemeStore.resetAll()clears overrides