Skip to content
Home Theme Gallery

Area chart

The custom element is <hui-area-chart>.

Overview

A curve with its area filled beneath, drawn in SVG from the server's JSON: one series or several, overlapping or stacked, solid or in a gradient. The curves are d3-shape's, as Recharts', so a monotone or natural line matches shadcn's to the control point.

Example

Monotone, gradient, fixed domain
Source
<hui-area-chart label="Share price, this week" curve="monotone" fill="gradient" fill-opacity="0.18"
grid hide-category-axis max="600" hide-tooltip-label style="height:200px">
<script type="application/json">{"series":[{"key":"price","label":"Price","colour":"var(--hui-chart-1)"}],"rows":[{"label":"Mon","price":412},{"label":"Tue","price":438},{"label":"Wed","price":395},{"label":"Thu","price":450},{"label":"Fri","price":420},{"label":"Sat","price":462}]}</script>
</hui-area-chart>

The Go template that renders it:

<hui-area-chart label="Share price, this week" curve="monotone" fill="gradient" fill-opacity="0.18"
grid hide-category-axis max="600" hide-tooltip-label style="height:200px">
<script type="application/json">{{ .Prices }}</script>
</hui-area-chart>

On a phone

The same thinning as the bar chart: labels that would collide are left out, the last is always kept, and none reaches past the element’s box.

Twelve months on a phone 375 px wide
Source
<hui-area-chart index="month" label="Visitors by month" curve="natural" grid style="height:220px">
<script type="application/json">{"series":[{"key":"desktop","label":"Desktop"}],"rows":[{"month":"January","desktop":186},{"month":"February","desktop":305},{"month":"March","desktop":237},{"month":"April","desktop":73},{"month":"May","desktop":209},{"month":"June","desktop":214},{"month":"July","desktop":190},{"month":"August","desktop":260},{"month":"September","desktop":240},{"month":"October","desktop":310},{"month":"November","desktop":280},{"month":"December","desktop":330}]}</script>
</hui-area-chart>

API

Attributes23
Attributes
NameTypeDefaultDescription
labelstring""Required. The chart's accessible name, and the caption of the data table.
indexstring"label"The row property that holds each category.
curve"natural" | "monotone" | "linear" | "step""natural"The interpolation between points: d3-shape's curves, as Recharts uses them. monotone never overshoots the data.
stroke-widthnumber2The line's width, in pixels.
stackedbooleanfalseSeries stack, each over the one before; otherwise they overlap.
fill"solid" | "gradient""solid"A flat tint, or a vertical gradient from the tint down to a sixth of it.
fill-opacitynumber0.4The fill's strength: all of a solid fill, the top of a gradient.
gridbooleanfalseDashed gridlines at each value tick.
value-axisbooleanfalseValue labels along the left.
hide-category-axisbooleanfalseLeaves the category labels out and keeps everything else.
barebooleanfalseNo axes, no grid, no margin: a sparkline.
minnumber-The value axis' low end.
maxnumber-The value axis' high end. With grid, the lines space evenly across the fixed domain.
marginstring"8 0 0 0"The plot's margin in pixels, CSS order.
tick-marginnumber8Space between the plot and its labels.
tick-lengthnumber-Shortens axis labels to this many characters; the tooltip and table keep them whole.
tooltip"index" | "item" | "none""index"Every series at the category, the series nearest the pointer, or nothing.
indicator"dot" | "line" | "dashed""dot"The marker beside each tooltip row.
hide-tooltip-labelbooleanfalseLeaves the category heading out of the tooltip.
legendbooleanfalseA legend under the plot.
cursorbooleanfalseA vertical rule at the active category.
formatstring-Intl.NumberFormat options as JSON.
localestringthe document's langThe locale values are formatted in.
Properties23
Properties
NameTypeDefaultDescription
labelstringas <code>label</code>Reflects to the label attribute.
indexstringas <code>index</code>Reflects to the index attribute.
curve"natural" | "monotone" | "linear" | "step"as <code>curve</code>Reflects to the curve attribute.
strokeWidthnumberas <code>stroke-width</code>Reflects to the stroke-width attribute.
stackedbooleanas <code>stacked</code>Reflects to the stacked attribute.
fill"solid" | "gradient"as <code>fill</code>Reflects to the fill attribute.
fillOpacitynumberas <code>fill-opacity</code>Reflects to the fill-opacity attribute.
gridbooleanas <code>grid</code>Reflects to the grid attribute.
valueAxisbooleanas <code>value-axis</code>Reflects to the value-axis attribute.
hideCategoryAxisbooleanas <code>hide-category-axis</code>Reflects to the hide-category-axis attribute.
barebooleanas <code>bare</code>Reflects to the bare attribute.
minnumberas <code>min</code>Reflects to the min attribute.
maxnumberas <code>max</code>Reflects to the max attribute.
marginstringas <code>margin</code>Reflects to the margin attribute.
tickMarginnumberas <code>tick-margin</code>Reflects to the tick-margin attribute.
tickLengthnumberas <code>tick-length</code>Reflects to the tick-length attribute.
tooltip"index" | "item" | "none"as <code>tooltip</code>Reflects to the tooltip attribute.
indicator"dot" | "line" | "dashed"as <code>indicator</code>Reflects to the indicator attribute.
hideTooltipLabelbooleanas <code>hide-tooltip-label</code>Reflects to the hide-tooltip-label attribute.
legendbooleanas <code>legend</code>Reflects to the legend attribute.
cursorbooleanas <code>cursor</code>Reflects to the cursor attribute.
formatstringas <code>format</code>Reflects to the format attribute.
localestringas <code>locale</code>Reflects to the locale attribute.
Events1
Events
NameDescription
hui-chart-focusThe reader moved to a category, by pointer or keyboard: its position, and the row as the server sent it. It bubbles and is composed. Announced, never stored: a host can mirror it elsewhere on the page.
Slots1
Slots
NameDescription
(default)One <script type="application/json"> holding series and rows. Replacing it, or its text, redraws the chart.
CSS custom properties2
CSS custom properties
NameDefaultDescription
--hui-chart-1 … --hui-chart-5the preset's violetSeries colours, by position, repeating after the fifth.
--hui-series-<key>-One series' colour, set from the host's stylesheet: --hui-series-mobile: var(--hui-chart-4). A colour field in the JSON wins over it.
::part() hooks13
::part() hooks
NameDescription
figureThe wrapper carrying role="figure" and the label.
plotThe <svg>, hidden from assistive technology.
gridThe gridlines group.
axis-xThe labels under the plot.
axis-yThe value labels beside it.
seriesOne group per series, with data-key.
areaA series' filled area, with data-series-index.
lineA series' line, with data-series-index.
active-dotThe 4px dot on the active point.
tableThe visually hidden data table.
tooltipThe tooltip, a manual popover.
legendThe legend row.
announcerThe visually hidden live region.

States

Natural, solid, with its months

One series against a fixed max, with fill-opacity making the fill flat rather than a gradient and tick-length shortening the month names.

Natural, solid, with its months
Source
<hui-area-chart index="month" label="Desktop visitors" fill-opacity="0.15" max="320" tick-length="3" style="height:200px">
<script type="application/json">{"series":[{"key":"desktop","label":"Desktop"}],"rows":[{"month":"January","desktop":186},{"month":"February","desktop":305},{"month":"March","desktop":237},{"month":"April","desktop":73},{"month":"May","desktop":209},{"month":"June","desktop":214}]}</script>
</hui-area-chart>

Stacked

stacked puts the series on top of one another, so the upper edge is the total, with a legend naming them.

Stacked
Source
<hui-area-chart index="month" label="Desktop and mobile visitors" stacked legend tick-length="3" style="height:200px">
<script type="application/json">{"series":[{"key":"desktop","label":"Desktop"},{"key":"mobile","label":"Mobile"}],"rows":[{"month":"January","desktop":186,"mobile":80},{"month":"February","desktop":305,"mobile":200},{"month":"March","desktop":237,"mobile":120},{"month":"April","desktop":73,"mobile":190},{"month":"May","desktop":209,"mobile":130},{"month":"June","desktop":214,"mobile":140}]}</script>
</hui-area-chart>

Server-side mechanics

The server writes the series and rows as JSON into the element's <script type="application/json"> child, in the order they are drawn - the chart never sorts, filters or aggregates. html/template escapes a Go value into that script: {{ .Chart }}. Replacing the child redraws the same element without animating; replacing the element draws the new one. Nothing the reader did survives a swap.

Accessibility

  • The chart is a figure named by label, and its data is a visually hidden table with that label as its caption; the SVG is hidden from the accessibility tree.
  • The plot is one tab stop: the arrow keys step the points with the tooltip following, and a polite live region reads each move.
  • A null breaks the line rather than joining across a missing value, and reads "No data" in the tooltip and table.
  • Under forced colours lines draw in CanvasText, each series after the first with its own dash pattern.
  • The first draw reveals left to right over 1500ms; under prefers-reduced-motion: reduce it is simply there, and no redraw after a swap animates.

Keyboard

Keyboard
KeysAction
TabFocuses the plot, one stop per chart, and shows the tooltip at the category the keyboard was last on.
Arrow Right, Arrow DownThe next category.
Arrow Left, Arrow UpThe previous category.
Home, EndThe first and the last category.
EscapeHides the tooltip; focus stays on the plot.

Gotchas

  • Areas overlap by default, later series over earlier, so a translucent fill lets the earlier show through. Stack them with stacked when they are parts of one total.
  • A gradient's ids repeat from chart to chart, which is safe: each chart's are inside its own shadow root.
  • Like every chart, it ships in home-ui-charts.js, not home-ui.js.