One theme across Apex products
Every Apex product resolves its colors, font and mode in the same order, and reads the same shared sources: the --apx-* CSS tokens, a theme registry every product on the page shares, and, with an add-on, the page's Ignite UI theme. State your brand once in one of them and every product on the page follows it. This page is the map; each product's own pages have the detail.
Key takeaways
- One order everywhere: an option you pass, then the product's own CSS, then the
--apx-*tokens, then a named theme, then Ignite UI, then the built-in defaults. - One set of tokens: declare
--apx-*on:rootand every product reads them, including the font, and in ApexCharts, ApexGantt and ApexGrid a corner radius factor. - One registry: a theme registered with
ApexCharts.registerTheme,ApexStock.registerThemeorregisterThemefromapex-commonscan be named from every product that takes a theme name. - One import per product for Ignite UI: each product has its own add-on, and none of them needs an extra licence key.
- After a theme change that does not render anything, call
refreshTokens()where the product has it, and re-render where it does not.
The order every product follows
Each color, the font and the mode resolve in one order, highest first. A higher source wins wherever it sets a value; a lower one fills only what nothing above it set.
| Rank | Source | Examples |
|---|---|---|
| 1 | An option you pass | colors on a chart, nodePalette on a Sankey, fontFamily, theme.mode |
| 2 | The product's own CSS | --apex-tree-*, --apex-sankey-*, --apex-gantt-*, --apexstock-*, --apexmaps-* and --ag-* variables; your rules for a chart's tooltip and menus |
| 3 | The family --apx-* tokens | --apx-accent, --apx-fore, --apx-series-1, --apx-font-family |
| 4 | A named theme or palette | A theme from the family registry, a product's built-in theme or preset, an explicit theme.palette |
| 5 | Ignite UI | The --ig-* tokens, with the product's add-on loaded |
| 6 | Built-in defaults | Each product's own palette and light mode |
"An option you pass" means passed, not "different from the default": an option set to its own default value still wins. ApexGrid themes through CSS only and has no named themes, so for a grid the order is your --ag-* tokens, then --apx-*, then Ignite UI, then its built-in values, with theme="dark" or theme="light" on the host fixing the mode.
The --apx-* tokens
Declare the tokens once, usually on :root. Custom properties inherit, so a token set on a container reaches only the products inside it.
:root {
--apx-accent: #0f766e;
--apx-fore: #1f2937;
--apx-grid: #e5e7eb;
--apx-surface: #ffffff;
--apx-series-1: #0f766e;
--apx-series-2: #d97706;
--apx-series-3: #2563eb;
--apx-font-family: 'Inter', system-ui, sans-serif;
--apx-radius-factor: 0.5;
}
| Token | Role |
|---|---|
--apx-accent | The color that means interactive or selected |
--apx-fore | Text, and anything that must stay legible on the surface |
--apx-grid | Hairlines: borders, gridlines, connectors |
--apx-surface | The plane content sits on |
--apx-series-1 to --apx-series-N | An ordered categorical palette, read up to its first gap |
--apx-font-family | The font, wherever you did not pass one |
--apx-radius-factor | Scales the product's built-in corner radii: 1 (or unset) changes nothing and 0 squares the corners. Radii you set in options are not scaled. Read by ApexCharts, ApexGantt and ApexGrid |
Which part of each product takes which token is on that product's theming page: ApexCharts, ApexGrid, ApexMaps, ApexTree, ApexSankey, ApexGantt and ApexStock. Each product also has a switch that stops it reading the tokens, such as theme.tokens: false on a chart or tokens="off" on a grid.
The shared theme registry
ApexCharts.registerTheme, ApexStock.registerTheme and registerTheme from apex-commons write to one registry that every Apex product on the page shares. Register a theme once and name it from any product:
import ApexCharts from 'apexcharts'
ApexCharts.registerTheme('brand', {
mode: 'light',
tokens: {
accent: '#0f766e',
fore: '#1f2937',
grid: '#e5e7eb',
surface: '#ffffff',
series: ['#0f766e', '#d97706', '#2563eb'],
},
})
| Product | How to name it | What it takes |
|---|---|---|
| ApexCharts | theme: { name: 'brand' } | The whole definition: mode, palette, tokens, monochrome, accessibility |
| ApexStock | theme: { preset: 'brand' }, or setThemePreset('brand') | mode, the accent, surface, fore and grid tokens, and the candle colors up and down when the entry has them |
| ApexSankey | theme: 'brand' | tokens.series for the nodes, tokens.fore for the labels, tokens.grid for the node borders |
| ApexTree | theme: 'brand' | The tokens |
| ApexGantt | theme: 'brand' | The tokens, and mode: 'dark' for the dark colors |
| ApexMaps | As a palette name, such as theme: { palette: 'brand' } | tokens.series |
| ApexGrid | No named themes | Use the --apx-* tokens |
- A named theme ranks below the
--apx-*tokens, so a token on:rootwins over the registry. ApexStock.registerThemewrites to the same registry, so registering a name there replaces an entry another product registered under it. Register each name once.ApexSankey.registerThemeis a separate, Sankey-only store for diagram fields such ascanvasStyle. Under the same name both apply, and the Sankey's own fields win where both set a value. A family theme'stokens.surfacedoes not paint the Sankey canvas:canvasStyledoes.ApexCharts.unregisterTheme(name)removes a theme for every product. ApexStock and ApexSankey have nounregisterTheme.
Register a brand theme across Apex products measures each of these in a browser, including the failures that raise no error.
Ignite UI: one import per product
Each product follows an Ignite UI theme on the page through its own add-on. The add-ons need no extra licence key. Without its add-on, a product ignores the --ig-* tokens, with no error. The --apx-* tokens and the registry work either way.
| Product | Add-on | Since | Guide |
|---|---|---|---|
| ApexCharts | import 'apexcharts/features/ignite-ui' | 8.8.0 | Using with Ignite UI |
| ApexGrid | import 'apex-grid/ignite-ui' | 4.0.0 | Using with Ignite UI |
| ApexMaps | import 'apexmaps/ignite-ui' | 1.3.0 | Using with Ignite UI |
| ApexTree | import 'apextree/ignite-ui' | 2.3.0 | Using with Ignite UI |
| ApexSankey | import 'apexsankey/ignite-ui' | 1.14.0 | Using with Ignite UI |
| ApexGantt | import 'apexgantt/ignite-ui' | 3.21.0 | Using with Ignite UI |
| ApexStock | import 'apexstock/ignite-ui' | 0.6.0 | Using with Ignite UI |
Import the add-on of every product on the page, before the first render. Some of them overlap (the tree, Sankey, Gantt and maps add-ons register one shared adapter, and in a bundler apexstock/ignite-ui loads the ApexCharts add-on itself), but an ApexCharts chart reads only its own add-on, and a map takes its basemap greys only from apexmaps/ignite-ui, so one import per product is the rule that always holds. With several tree, Sankey or Gantt add-ons on the page, the newest package's copy is the one they all read.
Ignite UI ranks just above the built-in defaults, so anything you already set, including the --apx-* tokens and a named theme, still wins. A product's designSystem: false (theme: { designSystem: false } on a chart, a map or a stock chart; design-system="off" on a grid) turns the Ignite UI layer off for that one instance and keeps the --apx-* tokens.
After a theme change
Products read the theme when they render. A stylesheet swap, such as an Ignite UI light to dark switch, or a class that changes the --apx-* tokens, renders nothing, so tell each product:
| Product | After a change |
|---|---|
| ApexCharts | chart.refreshTokens() |
| ApexTree | tree.refreshTokens() |
| ApexSankey | sankey.refreshTokens() |
| ApexGantt | gantt.render(), or gantt.update({}) |
| ApexStock | stock.update({}) |
| ApexMaps | map.updateOptions({}) |
| ApexGrid | Nothing to call: it themes in CSS and follows the change live |
const link = document.getElementById('ig-theme')
link.addEventListener(
'load',
() => {
chart.refreshTokens()
sankey.refreshTokens()
gantt.update({})
},
{ once: true }
)
link.href = '/themes/material-dark.css'
refreshTokens() re-reads the product's own CSS variables, the --apx-* tokens, the named theme and the Ignite UI theme, and repaints. A tree or Sankey keeps its nodes and view where they are. Call it as well when an add-on loads after the first render.
Frequently asked questions
Do I need Ignite UI to share one theme?
No. The --apx-* tokens and the theme registry are part of every product and need no other library. Ignite UI is one more source, read only when its add-on is loaded and its theme is on the page.
Why does my Sankey canvas stay transparent under a dark named theme?
Because a family theme's tokens.surface does not paint it. Register a SankeyTheme with a canvasStyle under the same name with ApexSankey.registerTheme; both registrations then apply. See Register a brand theme across Apex products.
Why did my chart lose its palette after I registered a stock preset?
ApexStock.registerTheme writes to the shared registry, and a preset under a name the chart already uses replaces the chart's entry, palette and tokens.series included. Register the name once, or give the stock preset its own name.