kandlo Docs

5. Theming

Last updated · 3 min read

On this page

The chart ships with 37 themes. A theme styles everything inside the chart page: the candles and lines on the canvas, the grid and axis text, indicator panes, the toolbar and menus, and the page background.

Because the chart runs in an iframe, your app's CSS cannot reach inside it, and the chart's CSS cannot reach your app. You style the chart by choosing a theme, or by adding your own theme to the chart's source.


1. Pick a theme#

Theme ids: call listThemes() (or the bridge command of the same name). A few of them: dark-blue (the default), light, midnight, graphite, ocean, oled, mono.

Where How
React <KandloChart theme="ocean" />. Changing the prop switches the theme.
Plain API createKandloChart(el, { theme: 'ocean' }), later chart.setTheme('midnight')
postMessage { kandlo: 1, id, type: 'setTheme', payload: { theme: 'midnight' } }
Chart page URL ?embed=1&theme=ocean

An unknown id is refused with unknown_theme (a URL value is ignored with a console warning).

The themeChange event (onThemeChange in React) reports every change, including one the user makes in the chart's own theme menu when the toolbar is shown (chrome="full", the default).

In an embed the theme your page sets is not saved: the next load starts from what your page passes again. The standalone chart page (opened directly, not embedded) saves the user's choice in its origin's localStorage under kandlo-theme, and starts from dark-blue when nothing is saved.

Follow the system light/dark setting#

JSX
import { useEffect, useState } from 'react';

function useSystemTheme(light = 'light', dark = 'dark-blue') {
  const query = '(prefers-color-scheme: dark)';
  const [isDark, setDark] = useState(() => window.matchMedia(query).matches);
  useEffect(() => {
    const m = window.matchMedia(query);
    const on = (e) => setDark(e.matches);
    m.addEventListener('change', on);
    return () => m.removeEventListener('change', on);
  }, []);
  return isDark ? dark : light;
}

// <KandloChart theme={useSystemTheme()} ... />

Around the chart#

  • chrome="minimal" (URL chrome=minimal) hides the chart's toolbar, zoom selector and tuning button, for pages that have their own controls.
  • The container <div> the component renders (data-kandlo-chart) is yours to style: border, radius, shadow, size. Give it a background close to the theme's so the area does not flash while the chart page loads. Most themes declare their page background as surfaces.bg in themes/<id>.theme.js (#06131d for ocean). The two base themes, dark-blue and light, take theirs from the base stylesheet instead.

2. Make your own theme#

A theme is one file, themes/<id>.theme.js. The canvas palette, the toolbar and menu styles, the theme picker entry, the stylesheet and the background illustration are all generated from it.

Shell
cp themes/_example.theme.js themes/brand.theme.js   # set id, constant, name, kind, cat, colours
# add "brand" to themes/_order.json, where it should sit in the theme picker
npm run themes                                      # validate and regenerate
npm run build && npm run build:interactions         # rebuild the bundles
npm run build:static                                # if you deploy the static site
  • id is what you pass as theme ('brand'); it appears in listThemes() after the rebuild.
  • themes/_order.json fixes the picker order. A theme missing from it stops npm run themes with Themes missing from themes/_order.json: brand.
  • npm run themes checks every theme before it writes anything, including a candle-contrast check: rising and falling candles must differ by at least 40 degrees of hue or enough brightness after the 3D shading (contrastWaiver turns a failure into a warning). npm run themes:check runs the same checks without writing.
  • Canvas colours (candles, grid, pane) are 6-digit hex without #; page colours (surfaces, backdrop, swatch) are CSS colours with #.

The full contract, field by field, is in themes/_schema.md (themes/_schema.md). Do not edit the generated regions in the sources (between // <<< generated: and // >>> generated: markers) or apps/web/assets/styles/theme-<id>.css; they are rewritten from themes/.

Offer only your themes#

The API accepts every theme that is built in. To present a short list in your app, keep your own list of ids and pass only those; with chrome="minimal" the chart's own theme menu is hidden, so users cannot pick others.

Type to search all guides.