Bar Chart

A composable bar chart with spring animations, stacked bars, horizontal orientation, and grouped series support

Installation

pnpm dlx shadcn@latest add @bklit/bar-chart

Usage

The Bar Chart uses the same composable API as the Line and Area charts. Build charts by combining components:

import {
  BarChart,
  Bar,
  BarXAxis,
  Grid,
  ChartTooltip,
} from "@bklitui/ui/charts";

const data = [
  { month: "Jan", revenue: 12000, profit: 4500 },
  { month: "Feb", revenue: 15500, profit: 5200 },
  // ... more data
];

export default function RevenueChart() {
  return (
    <BarChart data={data} xDataKey="month">
      <Grid horizontal />
      <Bar dataKey="revenue" fill="var(--chart-line-primary)" lineCap="round" />
      <Bar
        dataKey="profit"
        fill="var(--chart-line-secondary)"
        lineCap="round"
      />
      <BarXAxis />
      <ChartTooltip />
    </BarChart>
  );
}

See the charts gallery for stacked bars, horizontal layouts, gradients, patterns, and more.

Components

BarChart

The root component that provides context to all children.

PropTypeDefaultDescription
dataRecord<string, unknown>[]requiredArray of data points
xDataKeystring"name"Key in data for categorical axis values
marginPartial<Margin>{ top: 40, right: 40, bottom: 40, left: 40 }Chart margins
animationDurationnumber1100Animation duration in ms
aspectRatiostring"2 / 1"CSS aspect ratio
barGapnumber0.2Gap between bar groups (0-1 fraction of band width)
barWidthnumber-Fixed bar width in pixels (auto-sizes if not set)
orientation"vertical" | "horizontal""vertical"Bar chart orientation
stackedbooleanfalseStack bars instead of grouping them
stackGapnumber0Gap between stacked bar segments in pixels
classNamestring""Additional CSS class

Bar

Renders a bar for each data point with configurable styling and animations.

PropTypeDefaultDescription
dataKeystringrequiredKey in data for values
yAxisIdstring | number"left"Y-scale group for vertical biaxial charts (pair with YAxis)
fillstringvar(--chart-line-primary)Bar fill color (can be gradient/pattern url)
strokestring-Tooltip dot color. Use when fill is a gradient/pattern
lineCap"round" | "butt" | number"round"Bar end cap style or custom radius
animatebooleantrueEnable animation
animationType"grow" | "fade""grow"Animation style
fadedOpacitynumber0.3Opacity when another bar is hovered
staggerDelaynumberautoDelay between bars (auto-calculated based on bar count)
stackGapnumber0Gap between stacked bars in pixels
perspectivebooleanfalseMake this a 3D depth bar: trims the front-face top to meet the lid and forces a flat top. Pass true when pairing with BarDepthBack/BarDepthFront (see 3D Depth)
minBarHeightnumber0Minimum rendered height in px (non-stacked, vertical) — floors short/zero bars so they stay visible. Pair with <BarDepthProvider minBarHeight>

BarXAxis

Displays categorical labels along the x-axis (for vertical bar charts).

PropTypeDefaultDescription
tickerHalfWidthnumber50Width of ticker for fade calculation
showAllLabelsbooleanfalseShow all labels (may crowd)
maxLabelsnumber12Maximum labels to show

BarYAxis

Displays categorical labels along the y-axis (for horizontal bar charts).

PropTypeDefaultDescription
showAllLabelsbooleantrueShow all labels
maxLabelsnumber20Maximum labels to show

Grid

The Grid component now supports fadeVertical for vertical grid lines.

PropTypeDefaultDescription
horizontalbooleantrueShow horizontal grid lines
verticalbooleanfalseShow vertical grid lines
fadeHorizontalbooleantrueFade horizontal lines at left/right edges
fadeVerticalbooleanfalseFade vertical lines at top/bottom edges

Background

Pattern fill for the plot area when you omit Grid. See the Background utility and Pattern Background examples on the bar chart gallery.

BarDepthBack

Renders the 3D side + top faces. Place before <Bar> so the bar's front face occludes depth that would extend into the next column.

PropTypeDefaultDescription
dataKeystringrequiredKey in data for the bar value (match the sibling <Bar dataKey>)
colorstringvar(--chart-line-primary)Solid color for the side + top faces
colorAccessor(datum, index) => string-Per-bar color override; takes precedence over color

BarDepthFront

Renders the glossy glass sheen over the bar's fill. Place after <Bar>.

PropTypeDefaultDescription
dataKeystringrequiredKey in data for the bar value (match the sibling <Bar dataKey>)

BarPulse

Optional looping vertical sweep over a single active bar (e.g. a live value). Place after <BarDepthFront>.

PropTypeDefaultDescription
dataKeystringrequiredKey in data for the bar value
activeIndexnumber-Index (in the data array) of the bar to pulse
pulsePausedbooleanfalseFreeze the sweep while keeping the 3D/glass treatment

BarDepthProvider

Optional wrapper supplying shared depth config to every layer beneath it. Wrap it around <BarChart>, not inside it. Use it to split stacked bars (segmentsAccessor) and/or tune the baseline contact shadow (groundShadow).

PropTypeDefaultDescription
segmentsAccessor(datum) => { value: number; color: string }[]-Stacked segments (bottom→top) for each datum
groundShadownumber0.26Opacity (0–1) of the dark "contact shadow" that grounds each bar at the baseline. Set 0 to remove it (e.g. on bright fills).
minBarHeightnumber0Floors short/zero bars to a min px height so they stay visible. Pass the same value to <Bar minBarHeight>.

3D Depth & Glass Surfaces

Give bars a head-on 3D perspective and a glass-block sheen by layering BarDepthBack (side + top faces, before Bar) and BarDepthFront (front glass, after Bar). The layers read geometry from the chart context, so the only required prop is the matching dataKey.

Add perspective to the Bar and you're done — it shrinks the front face's top so the lid sits flush on the bar (instead of floating above it) and forces a flat top so the lid meets it with no gap. Always pass it when using the depth layers.

import {
  BarChart,
  Bar,
  BarDepthBack,
  BarDepthFront,
  BarXAxis,
  Grid,
  ChartTooltip,
} from "@bklitui/ui/charts";

<BarChart data={data} xDataKey="month">
  <Grid horizontal />
  <BarDepthBack dataKey="revenue" color="var(--chart-1)" />
  <Bar dataKey="revenue" fill="var(--chart-1)" perspective />
  <BarDepthFront dataKey="revenue" />
  <BarXAxis />
  <ChartTooltip />
</BarChart>;

Custom indicator (optional)

The 3D Depth gallery example pairs depth bars with a rising line indicator. Disable the default crosshair and dots on ChartTooltip, then render your own overlay via useChart and a portal — see Custom Indicator.

Color bars individually with colorAccessor:

<BarDepthBack
  dataKey="revenue"
  colorAccessor={(d) =>
    (d.revenue as number) >= 15000 ? "var(--chart-1)" : "var(--chart-3)"
  }
/>

Highlight a live / in-progress bar with BarPulse (render it after BarDepthFront):

<BarPulse dataKey="revenue" activeIndex={data.length - 1} />

Stacked bars (multiple data sources)

To give a stacked bar 3D depth, wrap the chart in BarDepthProvider with a segmentsAccessor returning one { value, color } per data source (bottom→top). The side face splits into a matching parallelogram per segment, and the lid takes the topmost segment's color. The depth's height is the sum of the segments, so you don't need a separate total column — just stack a <Bar> per source (each with perspective) in the same order:

<BarDepthProvider
  segmentsAccessor={(d) => [
    { value: d.desktop as number, color: "var(--chart-1)" },
    { value: d.mobile as number, color: "var(--chart-3)" },
  ]}
>
  <BarChart data={data} xDataKey="month" stacked>
    <BarDepthBack dataKey="desktop" />
    <Bar dataKey="desktop" fill="var(--chart-1)" perspective />
    <Bar dataKey="mobile" fill="var(--chart-3)" perspective />
    <BarDepthFront dataKey="desktop" />
    <BarXAxis />
    <ChartTooltip showCrosshair={false} showDots={false} />
  </BarChart>
</BarDepthProvider>;

Each bar gets a subtle dark "contact shadow" at the baseline so it reads as sitting on the axis. Tune or remove it with groundShadow on the provider (it reads strongest over bright fills):

<BarDepthProvider groundShadow={0.12}>
  {/* ...BarChart with depth layers... */}
</BarDepthProvider>

To keep zero or very short bars visible as a tiny bar instead of vanishing, set minBarHeight on both the <Bar> (floors the front face) and <BarDepthProvider> (floors the 3D surfaces) — they must match:

<BarDepthProvider minBarHeight={6}>
  <BarChart data={data} xDataKey="month">
    <BarDepthBack dataKey="value" color="var(--chart-1)" />
    <Bar dataKey="value" fill="var(--chart-1)" perspective minBarHeight={6} />
    <BarDepthFront dataKey="value" />
  </BarChart>
</BarDepthProvider>

Negative values are supported (bars grow downward from the baseline) as long as the chart's value scale includes negatives. See the charts gallery for a live 3D depth example.

Animation

Bars animate with the same easing as Line charts (cubic-bezier(0.85, 0, 0.15, 1)) for a smooth, organic feel. The stagger delay is automatically calculated based on the number of bars to ensure all animations complete within the total animation duration (~1.2s).

Grow Animation (Default)

Bars grow from zero to their final size:

<Bar dataKey="revenue" animationType="grow" />

Fade Animation

Bars fade in with a blur effect:

<Bar dataKey="revenue" animationType="fade" />

Custom Stagger

Stagger is calculated automatically, but you can override it:

// Override automatic stagger with custom delay
<Bar dataKey="revenue" staggerDelay={0.02} />

// No stagger (all bars animate together)
<Bar dataKey="revenue" staggerDelay={0} />

Line Cap Styles

Control the bar end style:

// Rounded caps (default) - full rounding
<Bar dataKey="revenue" lineCap="round" />

// Square caps - no rounding
<Bar dataKey="revenue" lineCap="butt" />

// Custom radius in pixels
<Bar dataKey="revenue" lineCap={4} />
<Bar dataKey="revenue" lineCap={8} />

Theming

The Bar Chart uses the same CSS variables as other charts:

:root {
  --chart-background: oklch(1 0 0);
  --chart-foreground: oklch(0.145 0.004 285);
  --chart-foreground-muted: oklch(0.55 0.014 260);
  --chart-line-primary: oklch(0.623 0.214 255);
  --chart-line-secondary: oklch(0.705 0.015 265);
  --chart-crosshair: oklch(0.4 0.1828 274.34);
  --chart-grid: oklch(0.9 0 0);
}

.dark {
  --chart-background: oklch(0.145 0 0);
  --chart-foreground: oklch(0.45 0 0);
  --chart-crosshair: oklch(0.45 0 0);
  --chart-grid: oklch(0.25 0 0);
}

Dependencies

This component requires the same packages as the other charts:

pnpm add @visx/shape @visx/scale @visx/responsive @visx/event @visx/grid d3-array motion react-use-measure