unit
Configuration Structure
unit: {}plotOptions
Settings for the unit chart (chart.type: 'unit') and its waffle preset (chart.type: 'waffle'). A unit chart draws one discrete mark per unit of value, so a count reads as a countable quantity rather than a single bar or slice.
layout
'grouped'How the marks are placed.
Available Options:
- 'grouped' (default): each category is its own cluster (a phyllotaxis blob), laid out in a row.
- 'packed': one shared blob, coloured by group and (with
sortByGroup) ordered so the minority nests in the centre. - 'columns': each category is a vertical bar built from stacked dots (a unit / waffle column) whose height encodes the count.
- 'grid': one lattice of cells filled in category order, a part-to-whole square "pie".
chart.type: 'waffle'presets this layout. - 'scatter': a beeswarm (or 2D value-value plot) that places marks on real numeric value axes.
- 'arc' (added 6.7): a parliament / hemicycle, seats in concentric arced rows across an annulus, filled in category order so each category is a contiguous wedge. See
arc. - 'custom' (added 6.9): the arrangement comes from your own provider. See
positions.
positions
undefinedlayout: 'custom' only. The layout provider: either a function returning plot-pixel positions, or the name of one registered with ApexCharts.registerUnitLayout.
plotOptions: {
unit: {
layout: 'custom',
positions: (objects, rect) => objects.map((o, i) => ({
id: o.id,
x: rect.x + (i % 20) * 14,
y: rect.y + Math.floor(i / 20) * 14
}))
}
}
It is called with (objects, rect) and returns [{ id, x, y, r? }]. objects carries identity and data per mark rather than just an index, so a provider can address a specific unit rather than a positional slot, and rect is the plot area in pixels.
A layout is objects in, positions out, and nothing else. It knows nothing about animation, because the engine already tweens position, radius and colour and already keeps each mark's identity across a relayout, so an arrangement the built-in layouts cannot express needs no new transition code.
A mark whose id the provider omits animates out through the existing exit path. Ids matching no mark are ignored.
Since 6.10 you usually do not have to write one: every shape in apexcharts/unit-shapes is exactly this kind of function, so it can be handed straight to positions with no registration step.
import { heart } from 'apexcharts/unit-shapes'
plotOptions: { unit: { layout: 'custom', positions: heart } }
transition
'group'How marks are matched between renders on an update, which decides which previous mark each new mark tweens from.
Available Options:
- 'group' (default): keyed per category, so a mark stays in its group and category-level enters/exits fade in and out.
- 'flow': keyed by global draw order, so the anonymous crowd migrates and recolours across a regroup (the circles-to-bars transition).
- 'identity': keyed by each datum's
id/name, so a specific mark migrates across any regroup or relayout keeping its colour and size. Requires the per-unit object form with unique ids/names.
shape
'circle'What one unit looks like. Independent of layout, which is where the units go, so positions: 'heart' with shape: 'pictogram' arranges glyphs into a heart and every other pairing works the same way.
Available Options:
- 'circle' (default)
- 'square' (see
borderRadius) - 'image': fetch a raster or multi-colour icon; configure it with
image. - 'pictogram': draw a vector glyph; configure it with
pictogram.
Prefer 'pictogram' for a monochrome glyph. Tinting an <image> needs an SVG filter per colour, and a filter forces an offscreen surface per element on every paint: 2000 tinted icons cost roughly 10x what 2000 drawn glyphs cost, and the gather drops frames well before 2000.
image
The icon used when shape: 'image'.
src
Icon URL or data URI.
width
Icon width in pixels.
height
Icon height in pixels.
tint
falseRecolour a monochrome icon to the category colour (or a per-unit fillColor) so the pictogram matches the legend. Leave off (default) for multi-colour icons that should keep their own colours.
pictogram
The glyph drawn when shape: 'pictogram'. One <path> per unit, filled in that unit's own colour, so it needs no request, no decode and no recolour filter. This is the shape that scales to thousands of units.
There is deliberately no size here. A glyph is fitted to the box the dot itself would have occupied, so size and spacing size a pictogram exactly as they size a dot, and swapping a circle for a glyph never re-flows the chart.
import { person } from 'apexcharts/pictograms'
plotOptions: {
unit: {
shape: 'pictogram',
pictogram: { mark: person },
},
}
One behaviour worth knowing: a filled glyph is hit-tested over its ink, not its box, so the tooltip tracks the glyph exactly and closes in the gaps between glyphs. Chunky glyphs therefore both read and behave better than fine ones; a hairline glyph feels flickery while sweeping a crowd. There is no portable fix, since pointer-events: bounding-box is Chrome-only.
mark
undefinedThe glyph. Accepts a mark from apexcharts/pictograms, the name of one registered with ApexCharts.registerUnitMark, a { path, viewBox?, fillRule? } object, raw path data, or an array of any of those (one per series).
A single datum overrides all of it with its own mark, exactly as fillColor overrides the category colour, so one crowd can mix glyphs:
series: [{
name: 'Households',
data: [
{ id: 'a', value: 1 },
{ id: 'b', value: 1, mark: 'house' },
],
}]
viewBox defaults to [0, 0, 100, 100], the catalog's convention.
fit
'contain'Which side of the glyph binds to the box the dot would have occupied.
Available Options:
- 'contain' (default): the longest side
- 'width'
- 'height'
scale
1Multiplier on the fitted size, for glyphs that read light against their neighbours.
padding
0Opens the lattice up, as a fraction of the pitch from 0 to 0.9.
fallback
'circle'Drawn when a mark cannot be resolved, e.g. a name that was never registered or was unregistered later.
Available Options:
- 'circle' (default)
- 'square'
size
'auto'Mark radius in pixels, or 'auto' (default) to size marks so the largest cluster fits.
columns
Options for the columns layout.
size
'inherit'The columns layout can size its dots independently of size.
Available Options:
- 'inherit' (default): use
size. - 'auto': size dots to fill the plot height.
- a number: pin a columns-only size. Circle / square only (image icons keep their intrinsic size).
grid
The grid (waffle) layout: one lattice of cells filled in category order.
columns
10Cells per row. Defaults to 10.
total
Fixed cell budget (e.g. 100 for a percentage waffle); a largest-remainder rule allocates the cells to categories so they sum exactly to the budget. Leave undefined for one cell per unit (respects unitValue / maxUnits).
fillFrom
'bottom'First row of the fill.
Available Options:
- 'bottom' (default)
- 'top'
split
falseSmall multiples: render one mini-waffle per category in a trellis instead of a single shared lattice. Each tile has total cells (default 100) and fills value/max of them; the rest show as a faint trackColor backdrop, and each tile carries its own label.
tileColumns
Small-multiple tiles per row. Undefined = auto (near-square).
max
Small-multiple value → filled-cell denominator. Undefined = the largest count (the leader fills its tile). Set to 100 for true "of 100" percentage tiles.
trackColor
Small-multiple empty ("track") cell colour. Undefined = neutral grey.
arc
Options for layout: 'arc' (parliament / hemicycle). Angles use the radialBar convention (0 at the top, clockwise). The default sweep is a top semicircle; a full circle is startAngle: 0, endAngle: 360. Added in 6.7.
startAngle
-90Sweep start angle in degrees (0 at the top, clockwise).
endAngle
90Sweep end angle in degrees. 90 gives a top semicircle.
innerRadiusRatio
0.4Donut hole, as the inner radius divided by the outer radius (0 fills the centre, closer to 1 is a thin band).
rows
'auto'Number of concentric seat rows, or 'auto' to size the dots as large as fit.
gather
The gather tween that moves marks between layouts on an update, and where entering marks come from. Added in 6.7.
easing
'outCubic'Travel curve for the gather tween. 'outCubic' (default) decelerates to a stop; 'inOutCubic' accelerates gently out of rest; 'outBack' overshoots each mark past its slot and springs back.
overshoot
1.70158Spring strength for easing: 'outBack' (how far each mark overshoots before settling).
enter
'burst'Where a fresh or appearing mark animates from. 'burst' (default) flies out from the cluster centre; 'fade' materialises in place; 'rise' fades in while drifting up into the slot.
scatter
The scatter layout places units on real value axes (needs the object-form data).
y
'lanes'Axis mode.
Available Options:
- 'lanes' (default): a beeswarm, a value axis with one category lane per series (see
orientationfor which axis carries the value). - 'value': a 2D value-value scatter — each datum's
x/yon two numeric axes, category = colour.
spread
'swarm'How equal values are separated within a lane.
Available Options:
- 'swarm' (default): anti-overlap packing off the lane centre.
- 'jitter': random lane spread.
orientation
'horizontal'Beeswarm orientation (y: 'lanes' mode only; ignored by the 2D value-value scatter). The value-axis keys (xMin / xMax / xTitle / xFormatter / tickAmount) describe the value axis in both orientations.
Available Options:
- 'horizontal' (default): value on the X axis, category lanes stacked on Y.
- 'vertical': value on the Y axis, category lanes as columns across X.
tickAmount
5Approximate number of value-axis ticks. Defaults to 5.
xMin
Fixed value-axis minimum. Undefined = a nice-numbered value derived from the data. An explicit bound is extended by whole tick steps when data would fall outside it, so every datum stays inside the axis.
xMax
Fixed value-axis maximum. Undefined = a nice-numbered value derived from the data. An explicit bound is extended by whole tick steps when data would fall outside it, so every datum stays inside the axis.
xTitle
Value-axis title, drawn along the value axis in either orientation.
xFormatter
Value-axis tick-label formatter, (value) => string.
yTickAmount
5Approximate number of Y-axis ticks (2D mode). Defaults to 5.
yMin
Fixed Y-axis minimum (2D mode). Undefined = nice-numbered from the data.
yMax
Fixed Y-axis maximum (2D mode). Undefined = nice-numbered from the data.
yTitle
Y-axis title (2D mode), drawn rotated at the left.
yFormatter
Y tick-label formatter, (value) => string.
sizeField
'z'Datum key holding the bubble size value. Defaults to 'z'.
sizeRange
[minRadius, maxRadius] in pixels: turns dots into area-scaled bubbles.
laneLabelWidth
Left-gutter width reserved for lane (category) labels in lanes mode.
gridlines
trueDraw the faint gridlines. Defaults to true.
sizeByValue
Opt-in bubble sizing: scale each dot's radius by its per-unit value (requires the object-form data, series: [{ data: [{ value }] }]). Circle shape only; the lattice is spaced for the largest bubble so dots never overlap. Ignored when there are no per-unit values.
enabled
falseTurn per-unit bubble sizing on.
maxRadius
'auto'Radius (px) for the largest value, or 'auto' to fit it to the plot.
minRadius
Radius (px) for the smallest value. Defaults to ~35% of maxRadius.
scale
'area'How the value maps to size.
Available Options:
- 'area' (default): bubble area proportional to value.
- 'linear': radius proportional to value.
spacing
1.05Packing gap factor between spiral shells (1 = dots touch).
borderRadius
Corner radius for shape: 'square'.
unitValue
1One mark represents this many units of value (waffle scaling).
maxUnits
5000Safety cap on the total number of marks; counts scale down proportionally above it.
sortByGroup
truepacked layout: order categories smallest-first so the minority group is centred.
clusterLabels
A per-cluster label: a curved arc above a blob, or a straight label above / below a bar.
show
Render the per-cluster label.
position
'top'Label placement relative to the cluster / bar. Defaults to 'top'. A 'bottom' label is always straight (the curved arc rides the top crown only).
curved
Bend the label into an arc that follows the top of the blob.
color
Label colour. Defaults to the cluster's own colour.
offsetY
Vertical offset of the label in pixels.
formatter
Return the label text: (name, { seriesIndex, value, percent, w }) => string.
external
Added in 6.10. Outer (name) labels, as pie and donut draw them: the label sits in the margin beside the shape and a leader line joins it to the colour band it names, so the crowd reads without a legend.
layout: 'custom' only, and best on a silhouette whose categories stack vertically (the default row ordering), since those alternate down the left and right gutters. A column-ordered shape sends each label to the side its own band sits on. The margin is taken off both sides before the dot size is chosen, so the shape stays centred but gets a little smaller: below roughly 520px of chart width, prefer a legend.
show
Render outer name labels instead of a legend.
show
Draw the leader line from the band to its label.
width
Leader line thickness in pixels.
color
Leader line colour. Defaults to the band's own colour.
gap
Air between the band's outermost dot and the leader line's bend.
length
Length of the leader line's run out to the label.
offsetX
Horizontal offset of the outer labels in pixels.
offsetY
Vertical offset of the outer labels in pixels.
tooltip
Per-unit (per-dot) tooltip.
formatter
Return the tooltip body for a single hovered dot. The dot's category is seriesIndex and its index within that category is dataPointIndex, so the formatter can index into per-unit data. Return a string or HTML. Defaults to "#<dataPointIndex+1> of <count>".