Bar Chart
A composable bar chart with spring animations, stacked bars, horizontal orientation, and grouped series support
Preview
Installation
pnpm dlx shadcn@latest add @bklit/bar-chartUsage
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.
| Prop | Type | Default | Description |
|---|---|---|---|
data | Record<string, unknown>[] | required | Array of data points |
xDataKey | string | "name" | Key in data for categorical axis values |
margin | Partial<Margin> | { top: 40, right: 40, bottom: 40, left: 40 } | Chart margins |
animationDuration | number | 1100 | Animation duration in ms |
aspectRatio | string | "2 / 1" | CSS aspect ratio |
barGap | number | 0.2 | Gap between bar groups (0-1 fraction of band width) |
barWidth | number | - | Fixed bar width in pixels (auto-sizes if not set) |
orientation | "vertical" | "horizontal" | "vertical" | Bar chart orientation |
stacked | boolean | false | Stack bars instead of grouping them |
stackGap | number | 0 | Gap between stacked bar segments in pixels |
className | string | "" | Additional CSS class |
Bar
Renders a bar for each data point with configurable styling and animations.
| Prop | Type | Default | Description |
|---|---|---|---|
dataKey | string | required | Key in data for values |
yAxisId | string | number | "left" | Y-scale group for vertical biaxial charts (pair with YAxis) |
fill | string | var(--chart-line-primary) | Bar fill color (can be gradient/pattern url) |
stroke | string | - | Tooltip dot color. Use when fill is a gradient/pattern |
lineCap | "round" | "butt" | number | "round" | Bar end cap style or custom radius |
animate | boolean | true | Enable animation |
animationType | "grow" | "fade" | "grow" | Animation style |
fadedOpacity | number | 0.3 | Opacity when another bar is hovered |
staggerDelay | number | auto | Delay between bars (auto-calculated based on bar count) |
stackGap | number | 0 | Gap between stacked bars in pixels |
perspective | boolean | false | Make 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) |
minBarHeight | number | 0 | Minimum 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).
| Prop | Type | Default | Description |
|---|---|---|---|
tickerHalfWidth | number | 50 | Width of ticker for fade calculation |
showAllLabels | boolean | false | Show all labels (may crowd) |
maxLabels | number | 12 | Maximum labels to show |
BarYAxis
Displays categorical labels along the y-axis (for horizontal bar charts).
| Prop | Type | Default | Description |
|---|---|---|---|
showAllLabels | boolean | true | Show all labels |
maxLabels | number | 20 | Maximum labels to show |
Grid
The Grid component now supports fadeVertical for vertical grid lines.
| Prop | Type | Default | Description |
|---|---|---|---|
horizontal | boolean | true | Show horizontal grid lines |
vertical | boolean | false | Show vertical grid lines |
fadeHorizontal | boolean | true | Fade horizontal lines at left/right edges |
fadeVertical | boolean | false | Fade 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.
| Prop | Type | Default | Description |
|---|---|---|---|
dataKey | string | required | Key in data for the bar value (match the sibling <Bar dataKey>) |
color | string | var(--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>.
| Prop | Type | Default | Description |
|---|---|---|---|
dataKey | string | required | Key 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>.
| Prop | Type | Default | Description |
|---|---|---|---|
dataKey | string | required | Key in data for the bar value |
activeIndex | number | - | Index (in the data array) of the bar to pulse |
pulsePaused | boolean | false | Freeze 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).
| Prop | Type | Default | Description |
|---|---|---|---|
segmentsAccessor | (datum) => { value: number; color: string }[] | - | Stacked segments (bottom→top) for each datum |
groundShadow | number | 0.26 | Opacity (0–1) of the dark "contact shadow" that grounds each bar at the baseline. Set 0 to remove it (e.g. on bright fills). |
minBarHeight | number | 0 | Floors 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