lineChart(), barChart() and pieChart() are presets: ready-made recipes over one function, chart(). When a recipe doesn’t fit, you cook with the same parts yourself: a list of axes, and a list of layers that draw on them.
Preset or compose?
Use a preset when your chart is a line, bar or pie chart. Presets take the familiar options, handle responsive options and give you the classic markup in one call.
Compose when you need something a preset can’t do:
- bars and a line in one chart,
- two value scales, like millimeters on the left and degrees on the right,
- several axes on one side, or an X axis at the top,
- your own layer next to the built-in ones.
Bars and a line on two axes
A climate chart: rain as bars on the left axis, temperature as a line on the right axis, each on its own scale.
import 'chartist/styles.css';
import {
autoScaleAxis,
axisGrid,
axisLabels,
bar,
cartesianAxes,
chart,
line,
stepAxis
} from 'chartist';
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'];
chart('#chart', {
data: {
labels: months,
series: [
// Salmon bars and a red line.
{
name: 'rain',
className: 'ct-series-b',
data: [64, 58, 70, 82, 104, 120]
},
{
name: 'temperature',
className: 'ct-series-a',
data: [1, 3, 8, 12, 16, 20]
}
]
},
axes: cartesianAxes([
{ id: 'month', side: 'bottom', type: stepAxis() },
{ id: 'mm', side: 'left', type: autoScaleAxis(), low: 0 },
{ id: 'celsius', side: 'right', type: autoScaleAxis(), low: 0 }
]),
layers: [
axisGrid({ axes: ['month', 'mm'] }),
bar({ series: ['rain'], x: 'month', y: 'mm' }),
line({
series: ['temperature'],
x: 'month',
y: 'celsius',
align: 'center'
}),
axisLabels()
]
});Three things make this work:
- Axes have ids.
cartesianAxes()takes a list of axes, each with anid, asideand atype. - Layers pick their series and axes.
bar({ series: ['rain'], x: 'month', y: 'mm' })draws the series namedrainagainst themonthandmmaxes. - Each axis scales to its own series. The
mmaxis only looks at the rain, thecelsiusaxis only at the temperature.
Axes
Every axis in cartesianAxes([...]) has:
| Field | What it is |
|---|---|
id |
The name layers use to draw on it. Ids must be unique |
side |
'bottom' or 'top' for an X axis, 'left' or 'right' for a Y axis |
type |
stepAxis(), autoScaleAxis() or fixedScaleAxis() |
On top of that, an axis takes the same options as axisX and axisY in the presets: offset, low, high, onlyInteger, ticks, showGrid, showLabel, labelTransform and the rest. Axes and scales explains the types and their options.
One thing goes beyond the presets: several axes can share a side. They stack outward in the order you list them, each with its own offset.
cartesianAxes([
{ id: 'month', side: 'bottom', type: stepAxis() },
// Both on the left: 'eur' next to the chart, 'usd' outside it.
{ id: 'eur', side: 'left', type: autoScaleAxis() },
{ id: 'usd', side: 'left', type: autoScaleAxis(), offset: 50 }
]);
Layers
Layers draw in the order you list them, each on top of the ones before. Put the grid first and the labels last.
| Layer | Draws | Options |
|---|---|---|
line() |
Lines, points and areas | series, x, y, align, lineSmooth, showLine, showPoint, showArea, areaBase |
bar() |
Bars | series, x, y, horizontalBars, stackBars, stackMode, seriesBarDistance, distributeSeries, offset |
axisGrid() |
Grid lines (g.ct-grids) |
axes (default: all), background |
axisLabels() |
Axis labels (g.ct-labels) |
axes (default: all), labels ('html' or 'svg') |
band() |
A band between two edges (g.ct-band) |
series, low, high, x, y, align, lineSmooth, mark |
series picks series by name or by index; leave it out and the layer draws all of them. x and y are axis ids; leave them out and the layer uses the first X and the first Y axis. An unknown name or id throws an error that names the layer. Grid and label layers draw for every axis unless you name some: the example draws the grid of month and mm only, so the right axis doesn’t add a second set of lines.
Bands have a guide of their own. Target lines, trend lines and axis titles are layers of @chartist-js/essentials, and work in composed charts the same way.
Series keep their place in the data: the temperature is the second series, so it would be ct-series-b even though it’s the only series its layer draws. Your series colors stay put when you move a series to another layer. (The example picks ct-series-e with className, the dark ink that stands apart from the red bars.)
Lining up with bars
Bars sit in the middle of each step, while line points sit at the start of it by default. align: 'center' moves the points to the bar centers, as in the example.
Bars grow from zero on their value axis, so make sure zero is on it: low: 0, or referenceValue: 0 to include zero and still scale to the data.
Grouped stacks
A bar layer with stackBars stacks all its series into one bar per label. For two stacks side by side, use two bar layers, one per group, and move them apart with offset (in px, along the label axis):
import 'chartist/styles.css';
import {
autoScaleAxis,
axisGrid,
axisLabels,
bar,
cartesianAxes,
chart,
stepAxis
} from 'chartist';
// New and returning customers per quarter: one stack per year.
chart('#chart', {
data: {
labels: ['Q1', 'Q2', 'Q3', 'Q4'],
series: [
{ name: '2024 new', data: [5, 3, 4, 6] },
{ name: '2024 returning', data: [2, 2, 3, 3] },
{ name: '2025 new', data: [4, 6, 5, 7] },
{ name: '2025 returning', data: [3, 4, 4, 5] }
]
},
axes: cartesianAxes({
x: { type: stepAxis() },
y: { type: autoScaleAxis(), low: 0 }
}),
layers: [
axisGrid(),
// Each layer stacks its own year; the offsets put the stacks side by side.
bar({
series: ['2024 new', '2024 returning'],
stackBars: true,
offset: -8
}),
bar({ series: ['2025 new', '2025 returning'], stackBars: true, offset: 8 }),
axisLabels()
],
// The bar chart class centers the X labels under the bars.
className: 'ct-chart-bar'
});Each layer stacks only the series it picks, and the value axis fits both stacks.
The rest of the config
Next to data, axes and layers, chart() takes:
| Option | What it does |
|---|---|
padding |
Space around the chart in px: a number, or { top, right, bottom, left } (default 15, 15, 5, 10) |
className |
Classes for the <svg>. By default the chart type’s class, from the layers |
width, height |
A fixed size; by default the chart fills its container |
labels |
'html' or 'svg' axis labels for every label layer |
The class matters for CSS: the default stylesheet aligns labels by chart type. Without a className, a chart with a bar() layer gets ct-chart-bar, which centers the X labels under the bars, a pie gets ct-chart-pie (or ct-chart-donut), and anything else gets ct-chart-line. A className of your own replaces it, so add the chart type’s class to it if you want that alignment.
In the API reference: chart(), layers and scales and axes.
Next: learn what each axis type does, or keep the chart up to date with new data.