Extending chart templates
June 23, 2026 · View on GitHub
Use this guide when a backend already exists and you want to add another chart type to it. For a new rendering target, start with Extending backends.
Table of Contents
- §1 Choose the chart name and channels
- §2 Author the template
- §3 Register the template
- §4 Add test data and gallery coverage
- §5 Cross-backend parity
- §6 Related
§1 Choose the chart name and channels
The public identity is the chart string on ChartTemplateDef. It must match chart_spec.chartType exactly, for example "Scatter Plot".
Pick only the channels the mark actually uses. Copy a similar template as a starting point:
| Family | Vega-Lite reference |
|---|---|
| Scatter / point | vegalite/templates/scatter.ts |
| Bar / column | vegalite/templates/bar.ts |
| Line / area | vegalite/templates/line.ts |
| Radial | vegalite/templates/pie.ts |
ECharts and Chart.js use the same ChartTemplateDef interface under their own templates/ folders.
§2 Author the template
ChartTemplateDef lives in packages/flint-js/src/core/types.ts.
import { ChartTemplateDef } from '../../core/types';
import { defaultBuildEncodings } from './utils';
export const dotPlotDef: ChartTemplateDef = {
chart: 'Dot Plot',
template: { mark: 'circle', encoding: {} },
channels: ['x', 'y', 'color', 'size', 'column', 'row'],
markCognitiveChannel: 'position',
declareLayoutMode: (channelSemantics, table, chartProperties) => {
// optional: banded axes, σ overrides, Q→O conversion
return { /* LayoutDeclaration */ };
},
instantiate: (spec, ctx) => {
defaultBuildEncodings(spec, ctx.resolvedEncodings);
// ctx.channelSemantics, ctx.layout, ctx.table, ctx.chartProperties, …
},
properties: [
{ key: 'opacity', label: 'Opacity', type: 'continuous',
min: 0.1, max: 1, step: 0.05, defaultValue: 1 },
],
};
Key rules
template— minimal native skeleton;instantiatefills encodings and mark properties.markCognitiveChannel— tells the compiler how readers decode value (affects zero baseline and Auto Layout Algorithm compression).instantiate— receives a deep clone oftemplateplusInstantiateContext(resolved encodings,ChannelSemantics,LayoutResult, data table, canvas size).- No semantic branching — read
ctx.channelSemantics[channel].format,.type,.zero, etc.; do not switch on raw field names or storage types.
Optional hooks: postProcess (after layout), encodingActions (shelf quick actions).
§3 Register the template
In packages/flint-js/src/<backend>/templates/index.ts:
- Import the new
*Defconstant. - Add it to the appropriate category array inside
*TemplateDefs(e.g.scatterTemplates). - Ensure
*GetTemplateDef(chartType)can find it:defs.find(t => t.chart === chartType).
Vega-Lite also runs withInjectedProperties() to attach shared facet and log-scale properties across templates. Follow existing entries in that file when your chart needs the same hooks.
§4 Add test data and gallery coverage
Generator pattern
The TestCase interface lives in packages/flint-js/src/test-data/types.ts.
Typical flow (see scatter-tests.ts, bar-tests.ts):
- Define a small parameter matrix (cardinality, color on/off, facet on/off).
- Export
gen<Chart>Tests(): TestCase[]withchartTypematchingChartTemplateDef.chart. - Register in
packages/flint-js/src/test-data/index.ts:
TEST_GENERATORS['Dot Plot'] = genDotPlotTests;
- Optionally add a page in
gallery-tree.tslisting the generator key.
Verify
npm run typecheck
npm run test
npm run site # Gallery → find your chart type
Review formatting, layout stretch, legends, and facet behavior across 3–6 representative cases.
§5 Cross-backend parity
The user-facing contract is that the same chartType string should work across assembleVegaLite, assembleECharts, and assembleChartjs when templates exist. In practice:
- Port to backends you need immediately; file follow-ups for the rest.
site/src/shared/supported-backends.tsfilters chart types per backend registry. A Vega-Lite-only template will not appear in ECharts until it is registered there too.
§6 Related
- Extending backends — full assembler wiring
- Semantic Type — what
channelSemanticscontains - Auto Layout Algorithm —
declareLayoutModeand stretch models - API reference —
chart_spec.chartTypeand encodings