Flux 2.0

Get started

Themes

One attribute changes every colour in the system. No component knows which theme is active, because no component references a colour — only a role.

Switching

html
<html lang="en" data-flux-theme="dark">

Light is the default and needs no attribute. Setting it explicitly is still useful when you are scoping a light region inside a dark page.

html
<!-- In <head>, inline, before any stylesheet or module script.
     In a Vite or React app this is index.html, not a component. -->
<script>
  const stored = localStorage.getItem('flux-theme');
  // Products that follow the OS preference replace 'light' with:
  // matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
  document.documentElement.setAttribute('data-flux-theme', stored ?? 'light');
</script>
js
// The theme control. Persist the choice so the script above restores it.
function setTheme(theme) {
  localStorage.setItem('flux-theme', theme);
  document.documentElement.setAttribute('data-flux-theme', theme);
}
Note
The script must run before the first paint. A theme applied after the stylesheet loads, or from a component’s effect, produces a visible flash of the wrong theme, which is worse than not offering the choice. Set the attribute on <html> directly rather than rendering it, because a framework does not own the root element.

The three themes

ThemeGroundFor
lightcanvas — the Kaptio off-whiteThe default. Carries the Flux 1.x values, so an existing page renders as it did.
darkneutral-950Dense product UI. Neutral rather than teal, so brand accents and status colours still read as signals.
deepprimary-800 — Kaptio tealSlides, marketing and brand surfaces. This is the ground Kaptio decks already use; 2.0 gives it a name and a full token set.
Careful
Deep is a brand ground, not a dark mode. Its tonal range is narrow, which is whylayer-03 aliases layer-02 andtext-placeholder aliases text-subtle. For information-dense interfaces, use dark.

All three at once

The same markup, three grounds, no theme-specific code.

Light

September departures

Twenty-four published, three awaiting supplier.

Dark

September departures

Twenty-four published, three awaiting supplier.

Deep

September departures

Twenty-four published, three awaiting supplier.

html
<div class="flux-card">
  <h3 class="flux-card__title">September departures</h3>
  <p class="flux-card__body">Twenty-four published, three awaiting supplier.</p>
  <div class="flux-card__footer">
    <button class="flux-button flux-button--sm">Publish</button>
    <span class="flux-badge flux-badge--pending">On request</span>
  </div>
</div>

Scoping a theme to a region

The attribute works on any element, not only the root.

html
<main>
  <!-- Inherits the page theme. -->
  <section class="report">…</section>

  <!-- A brand panel on a light page. -->
  <section data-flux-theme="deep" style="background: var(--flux-surface-page)">
    <h2>Kaptio Edge</h2>
  </section>
</main>

A scoped region must set its own background from --flux-surface-page or alayer-* token. Setting the attribute changes what the tokens resolve to; it does not paint anything by itself.

Following the system preference

css
/* Flux does not do this for you, deliberately: a product should decide
   whether its users want the OS preference honoured. */
@media (prefers-color-scheme: dark) {
  :root:not([data-flux-theme]) {
    color-scheme: dark;
  }
}

Most Kaptio product surfaces are light by default because they sit beside Salesforce, which is light. Honour the system preference where the surface stands alone — an internal tool, a dashboard someone keeps open all day — and let it be an explicit choice elsewhere.

Do and don’t

Do

  • Apply the theme attribute before first paint.
  • Persist the reader’s choice.
  • Give a scoped theme region its own background token.
  • Test a new component in all three themes before shipping it.

Don’t

  • Do not write theme-specific CSS in a component. If you need to, a token is missing.
  • Do not use deep for dense product UI.
  • Do not nest three layer levels on the deep theme.
  • Do not assume light. Anything that references a primitive will not follow the theme.