Bar Chart
Compare values across categories as columns or horizontal bars, side by side or stacked.
A bar chart compares values across categories, such as months, plans or regions. Each series draws one bar per category, and the bars stand side by side or stacked, as columns or as horizontal bars. Hover or tap a category, or focus the chart and use the arrow keys, to read its values in a card that trails beside it.
Installation
pnpm dlx shadcn@4.18.0 add @siteplane/bar-chartComplete the one-time setup first. Registry JSON lists source files and dependencies.
For this page’s examples, also install:
pnpm dlx shadcn@4.18.0 add @siteplane/card @siteplane/toggle-groupUsage
import { BarChart } from "@/siteplane/components/bar-chart";
<BarChart
data={[
{ month: "Jan", signups: 412 },
{ month: "Feb", signups: 486 },
{ month: "Mar", signups: 538 },
]}
label="Signups by month"
series={[{ key: "signups", label: "Signups" }]}
x="month"
/>;Multiple series
Pass several series to set their bars side by side in each category, in the order of the series. The legend is on by default when there is more than one series, and sits below the plot. A mouse over an entry steps the other series back; it does not toggle series.
- Opened
- Resolved
Stacked
With stacked, the bars of a category stack in the order of the series: positive values up from 0 and negative values down from it. A missing value adds nothing, and the tooltip lists each series’ own value, not the sum.
- New
- Reactivated
- Churned
Horizontal
orientation="horizontal" puts the categories down the left side and the values along the bottom, the way a ranking reads. xAxis still labels the categories and yAxis the values, and the Up and Down keys step through the categories. The labels at the left take at most 40% of the chart's width, and a longer label ends there in an ellipsis. The tooltip names the category in full.
Negative values
A value below 0 draws its bar on the other side of the 0 line. Give the series a negativeColor to color those bars and their tooltip rows; the bars above 0 keep the series color. Pass formatValue to format the values in the tooltip and on the value axis.
Categorical palette
A series that names no color takes a shade of the brand color, from strong to light, spread over the number of series, up to eight. With palette="categorical", each series takes its own chart color instead, --chart-1 to --chart-8, which suits unrelated categories such as regions. Both palettes repeat after the eighth series. A color on a series always wins.
- North America
- Europe
- Asia Pacific
Value labels
Set valueLabels to write the value of each bar at its end: above a column, below a column under 0, and beside a horizontal bar. A stack shows its sum, and the sum of its negative part below it. The labels use formatValue, as the tooltip does, and the chart keeps room for them inside the plot, so the highest label stays in the chart. When the labels do not all fit, every k-th category keeps its labels, one k for the whole chart; bars side by side that are too thin for their labels show none. While new data glides in, the labels wait and fade in where the bars come to rest.
- Online
- In store
Highlighted category
highlight takes the x value of one category and sets it apart, such as a day that is still running. Its bars take a soft hatched fill, quiet stripes of their own color over a light tint of it, so each series keeps its color, and its label on the axis and its value labels take the text color. The highlight is a look only: name the category in the data, such as Today, because the tooltip and screen readers read it as any other.
- Search
- Direct
Fill height
With height="fill", the chart is as tall as its box, which takes its height from the container: a flex item that grows, a grid cell, or a box with a height of its own. The chart never goes lower than minHeight, 240 px by default, and keeps that height until it has measured its box, on the server too. Its own content never makes the box taller, so a card can hand the chart whatever room the rest of the card leaves.
- Trial
- Paid
Changing data
When data changes, the bars glide to it. Bars are told by category and series, so a new bar grows from 0, a bar that is gone shrinks away, and the bars that stay glide; keep the text or date of a category the same from one data set to the next. The value axis moves with the bars, and axis labels fade through.
API reference
| Prop | Type | Default | Description |
|---|---|---|---|
Bar | readonly ChartDatum[] | required | Rows of the chart: an x value and one number per series. |
Bar | string | required | Key of the x value in each row: category text, or a Date, shown as a category in date order. |
Bar | readonly ChartSeries[] | required | The series to draw, in order. |
Bar | string | required | Accessible name of the chart. |
Bar | string | unset | Id of an element that describes the chart, read after the summary of the data that the chart gives screen readers. |
Bar | vertical | horizontal | vertical | vertical draws columns over a category axis along the bottom; horizontal puts the categories down the left side and the values along the bottom, so the grid lines run up and down. xAxis still labels the categories and yAxis the values. |
Bar | boolean | false | Stacks the bars of a category in the order of the series: positive values up from 0, negative values down from it. Otherwise they stand side by side. |
Bar | number | fill | 240 | Height of the chart in pixels, the legend included, or fill to take the height of its box down to minHeight; the width follows the container. |
Bar | number | 240 | With height fill, the least height of the chart in pixels, the legend included. |
Bar | boolean | false | Writes each bar's value at its end, or the sum of each sign of a stack, in the format of formatValue. Every k-th category keeps its labels when they do not all fit. |
Bar | ChartXValue | unset | The x value of one category to set apart: its bars take a hatched fill of their color, and its axis label and value labels the text color. |
Bar | brand | categorical | brand | brand shades the brand color from strong to light; categorical gives each series its own chart color. A series’ own color wins either way. |
Bar | boolean | true with more than one series | Lists the series below the plot. |
Bar | boolean | true | Grid lines at the value axis ticks: across the plot, or up and down in a horizontal chart. |
Bar | boolean | true | Labels along the x axis. |
Bar | boolean | true | Labels along the value axis. |
Bar | (value: number) => string | locale number (1,234.5); compact on the axis (1.2K) | Formats values in the tooltip and on the value axis. |
Bar | (value: ChartXValue) => string | text as given; a date as Jan 5, and Jan 5, 2026 in the tooltip | Formats x values on the axis and in the tooltip heading. |
Bar | string | en-US | Locale of numbers and dates. |
Bar | string | No data | Shown in place of the marks when there is nothing to draw. |
Bar | Partial<CartesianChartLabels> | English words | Replaces the words that the chart gives screen readers, each one on its own. Pass their translation when the application is in another language. |
Bar | string | unset | Additional classes. |
Chart | string | required | Key of the numbers of this series in each row. |
Chart | string | required | Name shown in the legend and the tooltip. |
Chart | string | palette color | A CSS color, such as var(--chart-3), that replaces the palette color of this series. |
Chart | string | unset | A CSS color for the bars of this series below 0 and their tooltip rows. Without it, a bar keeps the series color whatever its sign. |
Cartesian | string | chart | What screen readers call the chart. |
Cartesian | string | Use the arrow keys to move between data points. | Read after the description of the chart while it is a focus stop. An empty text leaves the hint out. |
Cartesian | string | to | Joins the first and the last x value in the summary of the data, as in Jan to Jun. |
Cartesian | string | lowest | Comes before the lowest value of each series in the summary. |
Cartesian | string | highest | Comes before the highest value of each series in the summary. |
BarChartProps exports these props. The chart core, @/siteplane/components/chart, installs with the Bar Chart and exports the shared types: ChartDatum, ChartSeries, ChartXValue, ChartPalette, CartesianChartLabels and CartesianChartProps. The chart renders a figure with the plot and, when it is shown, the legend; it takes no native props or ref beyond className and aria-describedby.
Usage notes
Use a bar chart to compare a few to a few dozen categories, side by side, stacked or as a ranking. For a trend over more than about 30 dates, a Line Chart or an Area Chart reads better. When readers must read exact values, show a Table instead: the axis gives a rough scale and the tooltip one category at a time. Several series share one value axis, which always includes 0.
On hover, focus or tap, the chart marks one category as active: the one under the pointer, or the one the keyboard has reached. A hairline crosshair runs through it, an inverse label on the axis names it, and in a column chart a dot per series glides to the end of its bar. The tooltip card sits beside the crosshair and trails it, and its values roll to the new ones. The other bars step back slightly, to 80%.
The plot is one focus stop. Focus from the keyboard marks the first category, and the arrow keys step through the categories: Left and Right, or Up and Down in a horizontal chart. Home and End jump to the ends, and Escape closes the tooltip. A tap or pen press pins a category until the next press elsewhere or Escape. Screen readers meet the plot as a chart named by label. Its description sums up the data with the first and the last category and the lowest and the highest value of each series; a chart with no value is described by emptyLabel. While the chart is a focus stop, a hint that the arrow keys move between the data points follows the description. labels replaces these words and the role description, for example with their translation. While the keyboard or a tap moves between the categories, a polite live region reads what the tooltip shows. The rows of the tooltip name each series, so the color never carries the information alone. A chart with no values is not a focus stop.
The chart has no click or selection API. New data animates with the Motion tokens (--motion-duration-value and --motion-ease-standard), and instantly under reduced motion: the system setting, html with data-motion-reduce="true" or SiteplaneMotionProvider preset="reduced". The tooltip comes from Tooltip. The chart opens and closes it itself, so it needs no TooltipProvider, which only shares hover delays between tooltips.
The chart draws its plot once it has measured the width of its container. Until then, and in the server HTML, it renders the box of the plot at its full height, the legend and what screen readers read, so nothing on the page moves when the plot appears. Text values on the x axis are categories, shown in the order given. Date values are shown in date order and written in UTC, so use dates at midnight UTC for days, such as new Date("2026-01-05"). A missing value leaves its bar out, and its series out of the tooltip for that category.