Bar Chart
- Stable
- WCAG 2.2 evidence
- RTL
A bar chart: bars per category with the title, range switch, KPI, legend and text alternative of the
card. Data driven: categories and series in, SVG out, rendered on the server from the same props. Accessibility: the figure is named by title, described by summary and backed by a data table (WCAG 1.1.1, 1.3.1). The plot is ONE
tab stop; Left and Right (vertical) or Up and Down (horizontal), Home, End, Page Up and Page Down move between categories, each
announced with all its values; the tooltip shows on hover and focus, stays while hovered and closes with Escape (2.1.1, 1.4.13).
Series differ by colour and fill pattern and the legend toggles them (1.4.1). The draw-in is behind motion-safe:. Category
labels rotate or thin out for the container width (1.4.10); the plot stays left-to-right in right-to-left pages. Consumer duties: a title that asks the question, a summary with the main message, units, meaningful series names, saying what a
highlighted bar stands for.
import { BarChart } from "@nexera-ui/react";- 13
- examples
- 32
- props
- 8
- live controls
- 1
- platform
- 9
- WCAG criteria
- 1
- block uses it
Try every prop. Copy the code.
Change the props and the code updates. Check light and dark, LTR and RTL, and phone width.
import { BarChart } from "@nexera-ui/react";
<BarChart />Examples 12
The same examples as Storybook, rendered live. Open Code to copy one.
Grouped
mode="grouped" (the default for several series): series side by side, each with its own colour AND fill pattern.
import { BarChart, type BarChartProps } from "@nexera-ui/react";
const MONTHS = ["Nov", "Dec", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct"];
const HIRES = [4, 3, 7, 5, 6, 8, 5, 9, 7, 6, 4, 8];
const verticalData = {
title: "Hires per month",
description: "Current month highlighted",
summary:
"72 hires in twelve months, 6 a month on average. June was the busiest month with 9; October, the current month, has 8.",
categories: MONTHS,
series: [{ name: "Hires", data: HIRES }],
highlightIndex: 11,
valueLabels: "highlighted",
labelledCategories: [7],
referenceLines: [{ value: 6, label: "Avg 6.0" }],
} satisfies BarChartProps;
<BarChart
title={verticalData.title}
summary={verticalData.summary}
categories={verticalData.categories}
series={verticalData.series}
/>;
Stacked
mode="stacked": series piled up, positive values up and negative values down, with the total above each stack.
import { BarChart, IconButton, type BarChartProps } from "@nexera-ui/react";
import { LuEllipsis } from "react-icons/lu";
const MONTHS = ["Nov", "Dec", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct"];
const HIRES = [4, 3, 7, 5, 6, 8, 5, 9, 7, 6, 4, 8];
const menu = <IconButton aria-label="More options" variant="ghost" icon={<LuEllipsis />} />;
const verticalData = {
title: "Hires per month",
description: "Current month highlighted",
summary:
"72 hires in twelve months, 6 a month on average. June was the busiest month with 9; October, the current month, has 8.",
categories: MONTHS,
series: [{ name: "Hires", data: HIRES }],
highlightIndex: 11,
valueLabels: "highlighted",
labelledCategories: [7],
referenceLines: [{ value: 6, label: "Avg 6.0" }],
} satisfies BarChartProps;
<BarChart
title={verticalData.title}
summary={verticalData.summary}
categories={verticalData.categories}
series={verticalData.series}
actions={menu}
/>;
Horizontal
orientation="horizontal": names down the side, bars growing to the end, values at the bar end and no value axis. Up and Down move.
import { BarChart, IconButton, type BarChartProps } from "@nexera-ui/react";
import { LuEllipsis } from "react-icons/lu";
const MONTHS = ["Nov", "Dec", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct"];
const HIRES = [4, 3, 7, 5, 6, 8, 5, 9, 7, 6, 4, 8];
const menu = <IconButton aria-label="More options" variant="ghost" icon={<LuEllipsis />} />;
const verticalData = {
title: "Hires per month",
description: "Current month highlighted",
summary:
"72 hires in twelve months, 6 a month on average. June was the busiest month with 9; October, the current month, has 8.",
categories: MONTHS,
series: [{ name: "Hires", data: HIRES }],
highlightIndex: 11,
valueLabels: "highlighted",
labelledCategories: [7],
referenceLines: [{ value: 6, label: "Avg 6.0" }],
} satisfies BarChartProps;
<BarChart
title={verticalData.title}
summary={verticalData.summary}
categories={verticalData.categories}
series={verticalData.series}
kpi={{ value: "14", label: "open roles" }}
actions={menu}
/>;
Diverging
Negative values grow below a stronger zero line; netLine draws the sum of each month as a line with markers.
import { BarChart, IconButton, type BarChartProps } from "@nexera-ui/react";
import { LuEllipsis } from "react-icons/lu";
const MONTHS = ["Nov", "Dec", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct"];
const HIRES = [4, 3, 7, 5, 6, 8, 5, 9, 7, 6, 4, 8];
const menu = <IconButton aria-label="More options" variant="ghost" icon={<LuEllipsis />} />;
const verticalData = {
title: "Hires per month",
description: "Current month highlighted",
summary:
"72 hires in twelve months, 6 a month on average. June was the busiest month with 9; October, the current month, has 8.",
categories: MONTHS,
series: [{ name: "Hires", data: HIRES }],
highlightIndex: 11,
valueLabels: "highlighted",
labelledCategories: [7],
referenceLines: [{ value: 6, label: "Avg 6.0" }],
} satisfies BarChartProps;
<BarChart
title={verticalData.title}
summary={verticalData.summary}
categories={verticalData.categories}
series={verticalData.series}
actions={menu}
/>;
Loading
import { BarChart, type BarChartProps } from "@nexera-ui/react";
const MONTHS = ["Nov", "Dec", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct"];
const HIRES = [4, 3, 7, 5, 6, 8, 5, 9, 7, 6, 4, 8];
const verticalData = {
title: "Hires per month",
description: "Current month highlighted",
summary:
"72 hires in twelve months, 6 a month on average. June was the busiest month with 9; October, the current month, has 8.",
categories: MONTHS,
series: [{ name: "Hires", data: HIRES }],
highlightIndex: 11,
valueLabels: "highlighted",
labelledCategories: [7],
referenceLines: [{ value: 6, label: "Avg 6.0" }],
} satisfies BarChartProps;
<BarChart
title={verticalData.title}
summary={verticalData.summary}
categories={verticalData.categories}
series={verticalData.series}
state={{ status: "loading" }}
/>;
Empty
import { BarChart, type BarChartProps } from "@nexera-ui/react";
const MONTHS = ["Nov", "Dec", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct"];
const HIRES = [4, 3, 7, 5, 6, 8, 5, 9, 7, 6, 4, 8];
const verticalData = {
title: "Hires per month",
description: "Current month highlighted",
summary:
"72 hires in twelve months, 6 a month on average. June was the busiest month with 9; October, the current month, has 8.",
categories: MONTHS,
series: [{ name: "Hires", data: HIRES }],
highlightIndex: 11,
valueLabels: "highlighted",
labelledCategories: [7],
referenceLines: [{ value: 6, label: "Avg 6.0" }],
} satisfies BarChartProps;
<BarChart
title={verticalData.title}
summary={verticalData.summary}
categories={[]}
series={[{ name: "Hires", data: [] }]}
state={{
status: "empty",
title: "No hires in this period",
description: "Try a longer period.",
}}
/>;
Error state
import { BarChart, Button, type BarChartProps } from "@nexera-ui/react";
const MONTHS = ["Nov", "Dec", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct"];
const HIRES = [4, 3, 7, 5, 6, 8, 5, 9, 7, 6, 4, 8];
const verticalData = {
title: "Hires per month",
description: "Current month highlighted",
summary:
"72 hires in twelve months, 6 a month on average. June was the busiest month with 9; October, the current month, has 8.",
categories: MONTHS,
series: [{ name: "Hires", data: HIRES }],
highlightIndex: 11,
valueLabels: "highlighted",
labelledCategories: [7],
referenceLines: [{ value: 6, label: "Avg 6.0" }],
} satisfies BarChartProps;
<BarChart
title={verticalData.title}
summary={verticalData.summary}
categories={verticalData.categories}
series={verticalData.series}
state={{
status: "error",
title: "Couldn't load hires",
description: "Check your connection and try again.",
action: (
<Button variant="secondary" size="sm">
Try again
</Button>
),
}}
/>;
Single point
One category: a single bar, never wider than 48 px.
import { BarChart } from "@nexera-ui/react";
<BarChart
title="Hires this month"
summary="8 hires in October."
categories={["Oct"]}
series={[{ name: "Hires", data: [8] }]}
description="October"
valueLabels="all"
/>;
Many points
200 bars: category labels thin out to what fits and the keys still reach every bar (Page Down skips 20).
import { BarChart } from "@nexera-ui/react";
const WEEKS = Array.from({ length: 200 }, (_, i) => `Week ${String(i + 1)}`);
<BarChart
title="Applications per week"
summary="Applications rise and fall in a nine-week cycle."
categories={WEEKS}
series={[{ name: "Applications", data: WEEKS.map((_, i) => 20 + ((i * 7) % 23)) }]}
description="Last 200 weeks"
valueLabels="none"
/>;
Long labels
Long category names rotate by 45 degrees (vertical) or are shortened beside the bars (horizontal); the table and tooltip keep the full names.
import { BarChart, type BarChartProps } from "@nexera-ui/react";
const MONTHS = ["Nov", "Dec", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct"];
const HIRES = [4, 3, 7, 5, 6, 8, 5, 9, 7, 6, 4, 8];
const verticalData = {
title: "Hires per month",
description: "Current month highlighted",
summary:
"72 hires in twelve months, 6 a month on average. June was the busiest month with 9; October, the current month, has 8.",
categories: MONTHS,
series: [{ name: "Hires", data: HIRES }],
highlightIndex: 11,
valueLabels: "highlighted",
labelledCategories: [7],
referenceLines: [{ value: 6, label: "Avg 6.0" }],
} satisfies BarChartProps;
<BarChart
title={verticalData.title}
summary={verticalData.summary}
categories={verticalData.categories}
series={verticalData.series}
/>;
Long labels horizontal
import { BarChart, type BarChartProps } from "@nexera-ui/react";
const MONTHS = ["Nov", "Dec", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct"];
const HIRES = [4, 3, 7, 5, 6, 8, 5, 9, 7, 6, 4, 8];
const verticalData = {
title: "Hires per month",
description: "Current month highlighted",
summary:
"72 hires in twelve months, 6 a month on average. June was the busiest month with 9; October, the current month, has 8.",
categories: MONTHS,
series: [{ name: "Hires", data: HIRES }],
highlightIndex: 11,
valueLabels: "highlighted",
labelledCategories: [7],
referenceLines: [{ value: 6, label: "Avg 6.0" }],
} satisfies BarChartProps;
<BarChart
title={verticalData.title}
summary={verticalData.summary}
categories={verticalData.categories}
series={verticalData.series}
orientation="horizontal"
hasTrack
/>;
Right to left
Right-to-left page: card, legend and table mirror, the plot keeps its left-to-right axis, digits follow the locale.
import { BarChart } from "@nexera-ui/react";
<BarChart
title="التعيينات مقابل المغادرات"
summary="تجاوزت التعيينات المغادرات في كل ربع."
categories={["الربع ٤", "الربع ١", "الربع ٢", "الربع ٣"]}
series={[
{ name: "التعيينات", data: [12, 19, 22, 21] },
{ name: "المغادرات", data: [9, 7, 6, 8], styleIndex: 3 },
]}
description="لكل ربع سنة"
mode="grouped"
valueLabels="all"
table={{ categoryLabel: "الربع", label: "عرض البيانات كجدول" }}
/>;
Props 32
Press "Try it" on a card to load that prop into the playground.
32 props shown
categories*Nexerareadonly string[]The category names, one per bar or group of bars ("Engineering", "Q1 26"), as drawn on the axis. The first value of every series belongs to the first category.
categoryTitlesNexerareadonly string[]The long form of each category for the tooltip, the point labels and the table.
series*Nexerareadonly ChartSeries[]The bars. One series is Chart/Bar/Vertical or Horizontal; several are grouped side by side (Grouped) or piled up
(Stacked). Negative values grow below the zero line (Diverging). null is a gap: no bar, "No data" in the table.
orientationNexera"vertical" | "horizontal"vertical draws the categories along the x axis; horizontal lists them
down the side with the bars growing to the end, which suits long names.
modeNexera"grouped" | "stacked"grouped puts the series side by side in each category; stacked piles them up (positive values up, negative values down).
highlightIndexNexeranumberIndex of the category to emphasise. Say what is highlighted in
the description or summary: emphasis is not meaning by itself.
valueLabelsNexera"none" | "all" | "highlighted"Numbers on the bars: all labels every bar (a stack gets its total), highlighted only the highlighted category. A horizontal
chart with labels draws no value axis, as Figma does.
labelledCategoriesNexerareadonly number[]Categories whose bars carry a value label in addition to the ones valueLabels chooses. Their labels are emphasised.
hasTrackNexerabooleanDraw a full-width track behind each horizontal bar and round the bars into pills.
referenceLinesNexerareadonly ChartReferenceLineSpec[]Horizontal reference lines (an average, a target) with a text label; vertical charts only.
netLineNexera{ readonly name: string; }Draw the net of each category (the sum of its bars) as a line with points over a vertical chart. Shown in the legend, the tooltip and the table under name.
patternsNexerabooleanDraw a fill pattern (hatch, dots) over every series except the first, in addition to its colour, so bars of different series can be told apart without colour (WCAG 1.4.1).
totalLabelNexerastringName of the stack total in the tooltip and the table. Translate it.
title*NexerastringChart title: the question the chart answers ("Headcount"). Required: it names the figure, the plot and the data table (WCAG 1.1.1).
descriptionNexeraReactNodeSecondary line under the title.
summary*NexerastringOne or two sentences with what the chart shows and its main message ("Headcount grew from 96 to 128 over twelve months"). Required: it describes the figure for assistive technology (WCAG 1.1.1); the data table has the details.
rangeNexeraChartRangePropsRange switch in the header: 3M, 6M, 12M. Pass the data of the chosen range back in.
actionsNexeraReactNodeExtra controls in the header, after the range switch.
kpiNexeraChartKpiPropsKPI row above the plot: the headline number with an optional label or change badge.
stateNexeraChartPlotStateThe state that replaces the plot: loading (skeleton), empty or error. A chart without a value to plot shows the empty state
by itself; pass { status: "empty", title, description, action } to give it your wording.
tableNexeraChartTableOptionsThe data table that is the text alternative: caption, first-column header and whether it is visible or only for assistive technology.
localeNexerastringLocale of digits and separators.
valueFormatNexeraNumberFormatOptionsIntl.NumberFormat options for values ({ style: "currency", currency: "PKR" }, { style: "percent" }). Serialisable, so it
works from a Server Component; formatValue needs a Client Component.
formatValueNexera(value: number) => stringFormats a value for tooltips, point labels and the table (full precision). Wins over valueFormat.
formatAxisValueNexera(value: number) => stringFormats an axis tick (short: "29M").
heightNexeranumberHeight of the plot in px. The card grows with the header, KPI and legend around it.
isLegendHiddenNexerabooleanHide the legend. The series stay named in the tooltip, the point labels and the table.
plotLabelNexerastringAccessible name of the plot group. Translate it.
noDataLabelNexerastringText for a missing value in the tooltip and the table. Translate it.
hiddenSeriesNexerareadonly string[]Names of the hidden series (controlled). Pair it with onHiddenSeriesChange.
defaultHiddenSeriesNexerareadonly string[]Names of the series hidden at first (uncontrolled).
onHiddenSeriesChangeNexera(hidden: readonly string[]) => voidCalled with the names of the hidden series when the user toggles a legend entry.
* Required. React Aria props shown are the ones most apps use; the component accepts the rest of its React Aria props too.
Accessible by default.
Built on React Aria, and covered by the WCAG 2.2 evidence generated on every build.
WCAG 2.2 evidence
7 direct · 2 supporting- 1.1.1Non-text ContentLevel A · tested directly
- 1.3.1Info and RelationshipsLevel A · tested directly
- 1.4.1Use of ColorLevel A · supporting test
- 1.4.10ReflowLevel AA · tested directly
- 1.4.13Content on Hover or FocusLevel AA · tested directly
- 2.1.1KeyboardLevel A · tested directly
- 2.3.3Animation from InteractionsLevel AAA · supporting test
- 4.1.2Name, Role, ValueLevel A · tested directly
- 4.1.3Status MessagesLevel AA · tested directly
Fits any width.
Nexera components respond to the space they are given. Drag the corner of the frame, or pick a width.
Styling hooks
Pass className to add Tailwind classes (merged last). State is exposed as data attributes, so you can style it with variants like data-pressed:.
<BarChart className="shadow-sm" />Used in blocks
Related components
- AccordionItemOne collapsible section of an FAQ or settings page.
- AreaChartA stacked area chart: layers piled up over time with the title, range switch, actions and legend of the card.
- AvailabilityRowOne person's availability across a window of the day: an avatar with initials and the name, and a timeline with the busy periods drawn as bars.
- AvatarA person or organisation shown as a photo, initials or an icon.
- AvatarGroupA row of overlapping avatars with a "+N" chip for the rest.
- AvatarLabelAn avatar with a name and an optional subtitle beside it, for a person in a list, a header or a mention.
- BadgeShort status or category label: `Tone` x `Variant` x `Size`, with an optional dot, leading icon and remove button.
- BadgeGroupA pill that pairs a small badge with a short message, for an announcement or a status line.