Charts
Bar Chart
A categorical comparison with visible axes and the same exact values in a native table.
When to use it: Use it to compare amounts across categories, especially when labels are long or ranking matters.
Example
import {
BarChart,
BarChartBar,
BarChartPlot,
ChartDescription,
ChartTable,
ChartTitle,
ChartTooltip,
} from "@comp0/react";
const performance = [
{ label: "Reliability", value: 96 },
{ label: "Accessibility", value: 91 },
{ label: "Interaction", value: 84 },
{ label: "Rendering", value: 78 },
] 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 (
<BarChart
values={performance}
categoryLabel="Measure"
valueLabel="Target met"
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">
Performance against target
</ChartTitle>
<BarChartPlot
aria-label="Horizontal bar chart comparing performance against target"
className="mx-auto mt-5 aspect-square w-full max-w-md overflow-visible"
>
{(bar) => (
<BarChartBar bar={bar} className="group outline-none">
<rect
x={bar.x}
y={bar.y}
width={bar.width}
height={bar.height}
className={`${colors[bar.index]} stroke-transparent group-data-active:stroke-zinc-950 dark:group-data-active:stroke-white`}
rx="1.5"
strokeWidth="2"
vectorEffect="non-scaling-stroke"
/>
</BarChartBar>
)}
</BarChartPlot>
<ChartDescription className="mt-5 text-sm text-zinc-600 dark:text-zinc-400">
Reliability and accessibility are closest to the target; rendering has the largest gap.
</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">Performance against target values</caption>
<thead>
<tr>
<th scope="col">Measure</th>
<th scope="col">Target met</th>
</tr>
</thead>
<tbody>
{performance.map((measure) => (
<tr key={measure.label}>
<th scope="row">{measure.label}</th>
<td>{formatPercent(measure.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" />
</BarChart>
);
}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.
BarChart
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.
BarChartPlot / BarChartBar
Horizontal SVG bars 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 BarChart with labelled values plus visible category and value axis labels.
- 2
Add the supporting parts
Add ChartTitle and BarChartPlot; wrap each rendered bar in BarChartBar so one bar 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 <BarChart values={performance} categoryLabel="Measure" valueLabel="Target met"> <ChartTitle>Performance against target</ChartTitle> <BarChartPlot aria-label="Horizontal bar chart comparing performance against target"> {(bar) => ( <BarChartBar bar={bar}> <rect x={bar.x} y={bar.y} width={bar.width} height={bar.height} /> </BarChartBar> )} </BarChartPlot> <ChartDescription>Rendering has the largest gap.</ChartDescription> <ChartTable> <caption>Performance values</caption> <thead> <tr> <th scope="col">Measure</th> <th scope="col">Target met</th> </tr> </thead> <tbody> {performance.map((measure) => ( <tr key={measure.label}> <th scope="row">{measure.label}</th> <td>{measure.value}%</td> </tr> ))} </tbody> </ChartTable> <ChartTooltip /> </BarChart>;
Keyboard
- ⇥
- Enters the chart at its current bar and leaves with one more Tab.
- ↓
- Moves to the next bar without wrapping.
- ↑
- Moves to the previous bar without wrapping.
- Home
- Moves to the first bar.
- End
- Moves to the last bar.
- 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 BarChartPlot a concise aria-label that identifies the chart type and subject.
- Wrap custom marks in BarChartBar to expose one roving tab stop; each bar 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 bars; the visible category axis must identify each one.
API reference
import { BarChart, BarChartBar, BarChartPlot, ChartDescription, ChartTable, ChartTitle, ChartTooltip } from "@comp0/react";BarChart
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 vertical category axis. |
valueLabel | string | Visible heading for the horizontal numeric axis. |
formatValue | (value: number) => string | Formats numeric axis ticks and table cells. |
ChartTitle
DOM elementNative figcaption that visibly names the figure.
BarChartPlot / BarChartBar
DOM elementHorizontal SVG bars with visible category and numeric axes.
| Prop | Type | Description |
|---|---|---|
aria-label | string | Concise text alternative naming the graphic and subject. |
xMin | number | Optional finite horizontal scale bounds that must contain every value and zero. |
xMax | number | Optional finite horizontal scale bounds that must contain every value and zero. |
xTickCount | number | Visible numeric-axis tick count; defaults to five. |
children | (bar: BarChartBarState) => ReactNode | Custom bar renderer receiving the category, value, and SVG geometry. |
bar | BarChartBarState | Bar state passed from the plot to BarChartBar. |
BarChartBar children | ReactNode | SVG shapes grouped into one named, keyboard-reachable bar. |
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 bar'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.
BarChartPlot / BarChartBar
| Style hook | Meaning |
|---|---|
[data-value] | The numeric value represented by this bar group. |
[data-active] | The bar currently reached by pointer or keyboard. |
ChartTooltip
| Style hook | Meaning |
|---|---|
[data-open] | A value tooltip is visible. |