Skip to content

BarChart

Compares lengths across categories. The mark that says how much, for data whose categories could be shuffled without losing anything.

tsx
import { BarChart } from 'neba';

<BarChart
  label="Deploys per team"
  categories={['Platform', 'Payments', 'Growth']}
  series={[{ name: 'Deploys', data: [318, 264, 197] }]}
  valueLabels="all"
/>;

The data model is the one every chart shares: series, categories, and a null that means a gap rather than a zero. It is written out on the LineChart page.

A bar's length is its value, which is why its axis starts at zero and cannot be talked out of it: crop the scale and a bar twice as long stops meaning twice as much. Where the categories have a natural order and the shape of the change is the point, a LineChart is the better mark.

Props

PropTypeDefaultDescription
series * NebaChartSeries[]The series. A colour is decided by a series' place in this array, so hiding one from the legend never repaints the survivors
categories(string | number | Date)[]The category axis' labels. Points may carry their own x instead
xAxisNebaChartAxisThe category axis
yAxisNebaChartAxisThe value axis
orientationshared'horizontal' | 'vertical''vertical'Which way the bars run. horizontal is right whenever the category names are words: a vertical chart gives each name the width of one bar
stackedboolean | 'full'falseGrouped bars answer "which series is bigger"; stacked bars answer "what is this total made of"; full asks about the mix
roundedbooleantrueCuts the corners off the data end of each bar. The baseline end stays square; a rounded foot makes the axis look scalloped
barSizenumbersize (md는 24px)How thick a bar may get, in pixels. Below the cap bars fill their share of the band; above it the leftover stays as air
valueLabels'none' | 'last' | 'extremes' | 'all''none'Which values are written on the bars. Eight bars with their numbers on them is a chart and a table at once; past a dozen it is neither
variantshared'solid' | 'outline' | 'text''text'Weight of the surface. A chart is a drawing rather than a sheet, so this defaults to text and a chart inside a Card draws no second edge. Use outline for one that stands alone
sizeshared'xs' | 'sm' | 'md' | 'lg' | 'xl''md'Axis type, line weight, marker size, and the height, when none is given
colorshared'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info''primary'The sheet's colour family. A series' colour does not come from here: the palette or series.color decides that
densityshared'default' | 'compact''default'Padding only: never the height, never the type scale
elevationshared0 | 1 | 2 | 30Drop shadow depth. 0 means no shadow at all
heightnumber | stringsizeHow tall the drawing is. The axis labels are drawn inside it, so a card sized to the chart is a card the chart fits in
labelstringlocale's wordThe chart's accessible name. Read out in place of the drawing, and the caption of the hidden data table under it. Without it the locale's generic word stands in, but what the chart is *of* can only be said here
formatIntl.NumberFormatOptionsHow numbers are written everywhere they appear: the axis, the tooltip, the value labels, the table. Without it, past ten thousand they are compacted (12.4K)
localestringThe language of the chart's own words and dates
legendboolean | NebaChartLegendseries ≥ 2Shown automatically from two series up and left off below that: a legend with one swatch restates the title
tooltipboolean | NebaChartTooltiptrueWhat the pointer uncovers. It never carries a value that is not also in the hidden table
emptyReactNodeWhat to draw when there is nothing to draw

Every native <div> attribute passes through, along with every Box prop. xAxis, yAxis, legend and tooltip take the same shapes they take on LineChart. See prop conventions for the shared axes.

Examples

orientation

horizontal is the right answer whenever the category names are words. A vertical chart gives each name the width of one bar; a horizontal one gives it a whole column, and the reading order runs the way a list does.

stacked

Grouped bars answer "which series is bigger here". Stacked bars answer "what is this total made of". 'full' normalises every bar to the same length, which asks about the mix instead: the value axis becomes a percentage, and the tooltip keeps the original number.

They are different questions and a chart should be asked only one at a time.

Negative values

A bar that goes the other way grows down from the same zero the others grow up from: the baseline is drawn where zero is, not at the bottom of the plot.

A point's own color overrides its series' for one bar, which is how a single value is marked without spending a second series on it.

valueLabels · rounded · barSize

valueLabels="all" is defensible here in a way it is not on a line chart: eight bars with their numbers on them is a chart and a table at once. Past about a dozen it stops being either, and extremes (the series' own high and low) is the one to reach for.

rounded cuts the corners off the data end of each bar; the baseline end stays square. barSize caps the thickness in pixels: below the cap bars fill their share of the band, above it the leftover stays as air. density="compact" widens that share.

tsx
<BarChart valueLabels="extremes" rounded={false} barSize={12} density="compact" />

Accessibility

  • The data is also rendered as a visually hidden table, captioned with label.
  • The plot is focusable; / (or / when horizontal) step the crosshair, Home / End jump to the ends, Escape clears it.
  • Touching bars are separated by a 2px gap of the surface colour rather than by a stroke, so nothing on the chart is ink that is not data.

Released under the MIT License