trellis
Configuration Structure
trellis: {}Split one series array into a grid of panels, each a real chart of the host's chart.type. Setting by (or row / column) makes the chart a trellis host, and the host owns everything shared between panels: the scale domains, the pixel-aligned plot rectangles, the colour-by-series-name map, the headers, one legend, one toolbar and the responsive column count.
Requires the Trellis feature, which is not in the default bundle: import 'apexcharts/features/trellis', or add dist/features/trellis.js after apexcharts.js on a script-tag page. See the Trellis guide for a walkthrough.
by
undefinedFacet accessor: the name of a key on each series object, or a function receiving (series, index) and returning the panel key.
series: [
{ name: 'Revenue', region: 'North', data: [/* … */] },
{ name: 'Revenue', region: 'South', data: [/* … */] },
],
trellis: {
by: 'region',
}
Series without the key repeat in every panel, which is how a target line or a benchmark reaches all of them at once. facet is the typed field on a series object, but any key name works from plain JavaScript.
Mutually exclusive with row / column.
row
undefinedRow facet accessor for a 2-D grid. With row and column set, the grid is every (row, column) combination in row-major order with a fixed column count: column labels draw once across the top, row labels once down the left, and panels shrink rather than re-column on resize.
A series carrying only the row key repeats across that row, which makes it a row-scoped reference series.
column
undefinedColumn facet accessor for a 2-D grid. See row. A series carrying only the column key repeats down that column.
emptyPanels
'placeholder'What to do with (row, column) combinations that carry no data.
Available Options:
- 'placeholder' (default) mounts a real empty panel at the shared geometry with a quiet
noData.textlabel - 'skip' keeps the slot with a tinted blank
- 'hide' keeps the slot with nothing in it
All three keep the slot, so the grid stays rectangular and the row and column labels keep lining up.
data
undefinedTidy-row input, an alternative to series: a row table pivoted by the by, x, y and seriesBy column names, all of which must be strings in this form.
trellis: {
data: [
{ month: '2025-01', region: 'North', revenue: 58 },
{ month: '2025-01', region: 'South', revenue: 42 },
],
by: 'region',
x: 'month',
y: 'revenue',
}
Rows win over series when both are given. Aggregation is out of scope: duplicate (panel, series, x) rows keep the last one and warn, so sum or average the rows yourself first.
x
undefinedName of the x-value column. Tidy-row form only.
y
undefinedName of the y-value column. Tidy-row form only.
seriesBy
undefinedName of the column whose values become series names. Tidy-row form only; absent means one series per panel, named after the y column.
columns
'auto'Column count. 'auto' fits as many minPanelWidth columns as the container holds and re-columns on resize; a number fixes the count.
minPanelWidth
220Narrowest a panel may get, in pixels. Drives columns: 'auto' and the responsive collapse.
gap
12Gap between cells, in pixels.
aspectRatio
1.6Panel width divided by panel height, used when no explicit height governs.
panelHeight
undefinedExplicit panel height in pixels. Takes precedence over aspectRatio and chart.height.
order
'first-seen'Panel order.
Available Options:
- 'first-seen' (default) follows the order the keys appear in the data
- 'asc' / 'desc' sort the keys
- an array of keys gives an explicit order
- a comparator receiving
(a, b)sorts them
limit
undefinedRender only the first N panels in order, and warn about the rest. Useful for a top-N grid without pre-slicing the data.
virtualize
'auto'Mount only the panels near the viewport.
Available Options:
- 'auto' (default) virtualizes once the grid exceeds 64 panels
- true always virtualizes
- false always renders eagerly
An unmounted cell keeps its header and a fixed-height skeleton, so page height and scroll position never shift. A panel scrolled out of view is destroyed with its view state stashed, and a remount restores its zoom window. getPanel(key) returns null for an unmounted panel.
scales
How each visual channel resolves across panels. A shared domain is what makes panels comparable; an independent one is what makes a small panel readable.
x
'shared'Available Options:
- 'shared' (default)
- 'independent'
y
'shared'Available Options:
- 'shared' (default) gives every panel the union domain, so a taller shape really is a bigger number
- 'independent' gives every panel its own domain
- 'independent-row' shares one domain per row (2-D grids)
- 'independent-column' shares one domain per column (2-D grids)
Panels stay pixel-aligned in every mode: a gutter pass measures each panel's axis-label width and pushes the widest as a shared floor, so the plot rectangles agree to the pixel. 'independent' and 'independent-column' show y labels on every panel, since the ticks differ; 'independent-row' keeps them on the first column, since the ticks along a row are identical.
color
'shared'Colour is keyed by series name across the whole grid, so one series is one colour in every panel.
Available Options:
- 'shared' (default)
size
'shared'Bubble radius resolution. Shared means one z extent for the grid, so bubble areas compare across panels.
Available Options:
- 'shared' (default)
header
The per-cell facet label above each panel.
show
trueAvailable Options:
- true (default)
- false
formatter
undefinedRewrite a header label. Receives (key, { dimension, index, count }) and returns the string to display. dimension names which accessor produced the key in a 2-D grid.
header: {
formatter: (key, { index, count }) => `${key} (${index + 1}/${count})`,
}
fontSize
undefinedFont size of the header label, as a CSS length.
fontWeight
undefinedFont weight of the header label.
color
undefinedColour of the header label.
axes
Axis-label policy across the grid.
labels
'edges'Available Options:
- 'edges' (default) shows y labels on the first column and x labels on each column's bottom panel
- 'all' labels every panel
- 'none' labels none
Label space is reserved on every panel whatever the setting, so panels stay aligned and switching modes never re-flows the grid.
legend
'shared'One legend for the grid, whose entries toggle a series name in every panel at once. Per-panel legends are hidden.
Available Options:
- 'shared' (default)
- 'none'
toolbar
'shared'One zoom, pan and reset toolbar for the grid.
Available Options:
- 'shared' (default)
- 'none'
tooltip
'panel'Where the tooltip card appears on hover. The crosshair sweeps every panel in all three modes.
Available Options:
- 'panel' (default) shows a card only in the hovered panel
- 'sync' shows each panel its own card at the hovered x
- 'grid' shows one card near the cursor with a row per panel at the hovered x
'grid' composes its rows from the panels' own tooltips, so every formatter is honoured. Virtualized panels that are not mounted contribute no row. Pair it with tooltip.compact when a normal card would cover a small panel.
zoom
'sync'Whether a zoom or pan in one panel moves the others.
Available Options:
- 'sync' (default)
- 'none'
promote
trueLet a click on a cell header expand that panel to the grid's full width, with an "All panels" breadcrumb back. Also available as promotePanel(key) and restorePanels().
Available Options:
- true (default)
- false
radiusByTotal
falsePie, donut and polarArea only: scale each panel's radius so its area is proportional to that panel's total.
Equal-size pies cannot encode magnitude, so a grid of them says nothing about which slice of the business is bigger. This is what makes a pie trellis honest.
Available Options:
- false (default)
- true
targetTicks
3Tick-interval target for the shared nice y scale. Panels are small, so the default of 3 intervals (about four labels) keeps the axis from outweighing the data.
panel
undefinedPer-panel option override, merged last. Receives (key, { index, seriesNames }) and returns a partial options object.
trellis: {
by: 'store',
panel: (key, { index }) => ({
colors: [scoreOf(key) >= 85 ? '#15803D' : '#DC2626'],
}),
}
Use it for what genuinely differs per panel. Anything shared belongs in the host options, so the trellis can keep the panels aligned.