Charts
Column Chart
A vertical categorical comparison with visible axes and the same exact values in a native table.
When to use it: Use it to compare a small set of short-labelled categories or emphasize change in magnitude.
Example
import {
ChartDescription,
ChartTable,
ChartTitle,
ChartTooltip,
ColumnChart,
ColumnChartColumn,
ColumnChartPlot,
} from "@comp0/react";
const traffic = [
{ label: "Direct", value: 42 },
{ label: "Search", value: 31 },
{ label: "Referrals", value: 18 },
{ label: "Social", value: 9 },
] as const;
const colors = [
"fill-teal-600 dark:fill-teal-400",
"fill-sky-600 dark:fill-sky-400",
"fill-violet-600 dark:fill-violet-400",
"fill-amber-500 dark:fill-amber-400",
] as const;
const formatPercent = (value: number) => `${value}%`;
export function Example() {
return (
<ColumnChart
values={traffic}
categoryLabel="Source"
valueLabel="Share"
formatValue={formatPercent}
className="w-full max-w-2xl rounded-lg has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-4 has-[:focus-visible]:outline-teal-600 dark:has-[:focus-visible]:outline-teal-400"
>
<ChartTitle className="text-base font-semibold text-zinc-950 dark:text-zinc-50">
Traffic by source
</ChartTitle>
<ColumnChartPlot
aria-label="Column chart comparing traffic share by source"
className="mx-auto mt-5 aspect-square w-full max-w-md overflow-visible"
>
{(column) => (
<ColumnChartColumn column={column} className="group outline-none">
<rect
x={column.x}
y={column.y}
width={column.width}
height={column.height}
className={`${colors[column.index]} stroke-transparent group-data-active:stroke-zinc-950 dark:group-data-active:stroke-white`}
rx="1.5"
strokeWidth="2"
vectorEffect="non-scaling-stroke"
/>
</ColumnChartColumn>
)}
</ColumnChartPlot>
<ChartDescription className="mt-5 text-sm text-zinc-600 dark:text-zinc-400">
Direct visits are the largest source, while social accounts for less than one tenth.
</ChartDescription>
<ChartTable className="mt-4 w-full border-collapse text-left text-sm [&_td]:border-t [&_td]:border-zinc-200 [&_td]:py-2 [&_th]:border-zinc-200 [&_th]:py-2 dark:[&_td]:border-zinc-800 dark:[&_th]:border-zinc-800">
<caption className="sr-only">Traffic source values</caption>
<thead>
<tr>
<th scope="col">Source</th>
<th scope="col">Share</th>
</tr>
</thead>
<tbody>
{traffic.map((source) => (
<tr key={source.label}>
<th scope="row">{source.label}</th>
<td>{formatPercent(source.value)}</td>
</tr>
))}
</tbody>
</ChartTable>
<ChartTooltip className="pointer-events-none z-50 rounded-md bg-zinc-950 px-2 py-1 text-sm text-white shadow-lg dark:bg-zinc-50 dark:text-zinc-950" />
</ColumnChart>
);
}Anatomy
Dashed frames are invisible state providers; shaded shapes own real DOM. Numbered pins match the list below.
A wireframe sketch of the assembled component. Each numbered marker matches a part in the list that follows.
ColumnChart
Native figure sharing categorical values, labels, and formatting with every part. Owns a DOM element.
ChartTitle
Native figcaption that visibly names the figure. Owns a DOM element.
ColumnChartPlot / ColumnChartColumn
Vertical SVG columns with visible category and numeric axes. Owns a DOM element.
ChartDescription
Visible prose summarizing the important comparison. Owns a DOM element.
ChartTable
Native table composed with an explicit caption, headers, and rows from the chart values. Owns a DOM element.
ChartTooltipOptional
Optional floating value label shown on hover or focus. Owns a DOM element.
Step by step
- 1
Add the main part
Start ColumnChart with labelled values plus visible category and value axis labels.
- 2
Add the supporting parts
Add ChartTitle and ColumnChartPlot; wrap each rendered column in ColumnChartColumn so one column is tabbable and arrow keys reveal the rest.
- 3
Make the behavior clear
Add ChartDescription and ChartTable for persistent context and exact values; optionally add ChartTooltip for pointer and keyboard details.
Exampletsx <ColumnChart values={traffic} categoryLabel="Source" valueLabel="Share"> <ChartTitle>Traffic by source</ChartTitle> <ColumnChartPlot aria-label="Column chart comparing traffic share by source"> {(column) => ( <ColumnChartColumn column={column}> <rect x={column.x} y={column.y} width={column.width} height={column.height} /> </ColumnChartColumn> )} </ColumnChartPlot> <ChartDescription>Direct visits are the largest source.</ChartDescription> <ChartTable> <caption>Traffic source values</caption> <thead> <tr> <th scope="col">Source</th> <th scope="col">Share</th> </tr> </thead> <tbody> {traffic.map((source) => ( <tr key={source.label}> <th scope="row">{source.label}</th> <td>{source.value}%</td> </tr> ))} </tbody> </ChartTable> <ChartTooltip /> </ColumnChart>;
Keyboard
- ⇥
- Enters the chart at its current column and leaves with one more Tab.
- →
- Moves to the next column without wrapping.
- ←
- Moves to the previous column without wrapping.
- Home
- Moves to the first column.
- End
- Moves to the last column.
- Esc
- Dismisses an open ChartTooltip.
Forms and accessibility
Charts are descriptive content and do not create form values.
Accessibility checklist
- Keep the category and value axis labels visible; tick labels should use the same units as the table.
- Give ColumnChartPlot a concise aria-label that identifies the chart type and subject.
- Wrap custom marks in ColumnChartColumn to expose one roving tab stop; each column receives a formatted category-and-value name.
- ChartTooltip is an optional visual enhancement for hover and focus; never make it the only source of a value.
- Include ChartTable when exact values matter; its native headers preserve category and value relationships during screen-reader navigation.
- Do not use color as the only way to distinguish columns; the visible category axis must identify each one.
API reference
import { ChartDescription, ChartTable, ChartTitle, ChartTooltip, ColumnChart, ColumnChartColumn, ColumnChartPlot } from "@comp0/react";ColumnChart
DOM elementNative figure sharing categorical values, labels, and formatting with every part.
| Prop | Type | Description |
|---|---|---|
values | readonly CategoricalChartValue[] | Category labels and finite numeric values. |
categoryLabel | string | Visible heading for the horizontal category axis. |
valueLabel | string | Visible heading for the vertical numeric axis. |
formatValue | (value: number) => string | Formats numeric axis ticks and table cells. |
ChartTitle
DOM elementNative figcaption that visibly names the figure.
ColumnChartPlot / ColumnChartColumn
DOM elementVertical SVG columns with visible category and numeric axes.
| Prop | Type | Description |
|---|---|---|
aria-label | string | Concise text alternative naming the graphic and subject. |
yMin | number | Optional finite vertical scale bounds that must contain every value and zero. |
yMax | number | Optional finite vertical scale bounds that must contain every value and zero. |
yTickCount | number | Visible numeric-axis tick count; defaults to five. |
children | (column: ColumnChartColumnState) => ReactNode | Custom column renderer receiving the category, value, and SVG geometry. |
column | ColumnChartColumnState | Column state passed from the plot to ColumnChartColumn. |
ColumnChartColumn children | ReactNode | SVG shapes grouped into one named, keyboard-reachable column. |
ChartDescription
DOM elementVisible prose summarizing the important comparison.
ChartTable
DOM elementNative table composed with an explicit caption, headers, and rows from the chart values.
| Prop | Type | Description |
|---|---|---|
children | ReactNode | Native caption, thead, tbody, and optional tfoot markup. |
ChartTooltip
OptionalDOM elementOptional floating value label shown on hover or focus.
| Prop | Type | Description |
|---|---|---|
placement | PopoverPlacement | Side of the active mark; defaults to "top". |
offset | number | Distance from the active mark; defaults to eight pixels. |
children | ReactNode | (details: ChartValueDetails) => ReactNode | Custom content receiving the active column's formatted details. |
Style hooks
Attributes that appear while a state is true. Target them with Tailwind data variants such as data-open:bg-zinc-100, or with any CSS selector.
ColumnChartPlot / ColumnChartColumn
| Style hook | Meaning |
|---|---|
[data-value] | The numeric value represented by this column group. |
[data-active] | The column currently reached by pointer or keyboard. |
ChartTooltip
| Style hook | Meaning |
|---|---|
[data-open] | A value tooltip is visible. |