Bar Chart
A composable bar chart with spring animations, stacked bars, horizontal orientation, and grouped series support
Preview
Installation
pnpm dlx shadcn@latest add https://ui.bklit.com/r/bar-chart.jsonUsage
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>
);
}Stacked Bars
Use the stacked prop to stack bars on top of each other. Add stackGap to create visual separation between segments, allowing each bar to have its own rounded corners.
<BarChart data={data} xDataKey="month" stacked stackGap={3}><Grid horizontal /><Bar dataKey="desktop" fill="hsl(217, 91%, 60%)" lineCap={4} stackGap={3} /><Bar dataKey="mobile" fill="hsl(217, 91%, 75%)" lineCap={4} stackGap={3} /><BarXAxis /><ChartTooltip /></BarChart>Horizontal Bars
Use orientation="horizontal" to create horizontal bar charts with categories on the Y-axis.
<BarChart data={data} xDataKey="browser" orientation="horizontal" margin={{ left: 80 }}><Grid horizontal={false} vertical fadeVertical /><Bar dataKey="users" fill="hsl(217, 91%, 60%)" lineCap={4} /><BarYAxis /><ChartTooltip showCrosshair={false} /></BarChart>90 Days of Data
A single series bar chart showing 90 days of data with square caps.
<BarChart data={dailyData} xDataKey="day" barGap={0.1}><Grid horizontal /><Bar dataKey="value" lineCap="butt" /><BarXAxis maxLabels={8} /><ChartTooltip /></BarChart>Gradients and Patterns
Use visx gradient and pattern components to create custom bar fills. Place them as children of BarChart and reference them by ID.
Gradient Fill
Use the stroke prop to set the tooltip dot color when using gradient fills.
import { LinearGradient } from "@bklitui/ui/charts";<BarChart data={data} xDataKey="month"><LinearGradient id="barGradient" from="hsl(217, 91%, 60%)" to="hsl(280, 87%, 65%)" /><Grid horizontal /><Bar dataKey="revenue" fill="url(#barGradient)" stroke="hsl(217, 91%, 60%)" lineCap={4} /><BarXAxis /><ChartTooltip /></BarChart>Pattern Fill
Use the stroke prop to set a solid tooltip dot color when using pattern fills.
import { PatternLines } from "@bklitui/ui/charts";<BarChart data={data} xDataKey="month"><PatternLines id="barPattern" height={8} width={8} stroke="hsl(217, 91%, 60%)" strokeWidth={2} orientation={["diagonal"]}/><Grid horizontal /><Bar dataKey="revenue" fill="url(#barPattern)" stroke="hsl(217, 91%, 60%)" lineCap={4} /><BarXAxis /><ChartTooltip /></BarChart>Available Fills
Gradients (from @visx/gradient):
LinearGradient- Custom linear gradient withfrom,to, and optionalfromOpacity/toOpacityRadialGradient- Radial gradient withfrom,to, andr(radius)- Pre-built:
GradientDarkgreenGreen,GradientOrangeRed,GradientPinkBlue,GradientPurpleTeal,GradientTealBlue, etc.
Patterns (from @visx/pattern):
PatternLines- Diagonal, horizontal, or vertical linesPatternCircles- Dot patternPatternHexagons- Hexagonal patternPatternWaves- Wave pattern
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 |
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 |
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 |
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} />Examples
Stacked with Legend
const legendItems = [{ label: "Desktop", value: 0, color: "hsl(217, 91%, 60%)" },{ label: "Mobile", value: 0, color: "hsl(217, 91%, 75%)" },];<div><BarChart data={data} xDataKey="month" stacked stackGap={3}> <Grid horizontal /> <Bar dataKey="desktop" fill="hsl(217, 91%, 60%)" lineCap={4} stackGap={3} /> <Bar dataKey="mobile" fill="hsl(217, 91%, 75%)" lineCap={4} stackGap={3} /> <BarXAxis /> <ChartTooltip /></BarChart><Legend items={legendItems} className="flex-row justify-center gap-6"> <LegendItem className="flex items-center gap-2"> <LegendMarker /> <LegendLabel /> </LegendItem></Legend></div>Narrow Gaps
<BarChart data={data} xDataKey="month" barGap={0.1}><Grid horizontal /><Bar dataKey="revenue" fill="var(--chart-line-primary)" lineCap="round" /><BarXAxis /><ChartTooltip /></BarChart>Custom Tooltip
<BarChart data={data} xDataKey="month"><Grid horizontal /><Bar dataKey="revenue" fill="var(--chart-line-primary)" lineCap="round" /><BarXAxis /><ChartTooltip rows={(point) => [ { color: "var(--chart-line-primary)", label: "Revenue", value: `$${point.revenue?.toLocaleString()}`, }, ]}/></BarChart>No Gap with Custom Line Indicator
A bar chart with zero gap between bars, gradient fill, and a custom horizontal line indicator. Each bar has its own line that rises from the bottom on hover.
// Each bar gets an animated line that rises on hoverfunction AnimatedBarLine({ barX, barTopY, barBottomY, width, isHovered }) {const animatedY = useSpring(barBottomY, { stiffness: 300, damping: 30 });useEffect(() => { animatedY.set(isHovered ? barTopY : barBottomY);}, [isHovered, barTopY, barBottomY]);return ( <motion.rect x={barX} width={width} height={2} fill="white" style={{ opacity: isHovered ? 1 : 0, y: animatedY }} />);}// Renders a line indicator for each barfunction BarLineIndicators({ data }) {const { barScale, bandWidth, innerHeight, yScale, hoveredBarIndex } = useChart();return data.map((d, i) => ( <AnimatedBarLine key={d.month} barX={barScale(d.month)} barTopY={yScale(d.revenue)} barBottomY={innerHeight} width={bandWidth} isHovered={hoveredBarIndex === i} />));}<BarChart data={data} xDataKey="month" barGap={0}><LinearGradient id="gradient" from="var(--chart-3)" to="transparent" /><Grid horizontal /><Bar dataKey="revenue" fill="url(#gradient)" lineCap="butt" stroke="var(--chart-3)" /><BarXAxis /><ChartTooltip showCrosshair={false} showDots={false} /><BarLineIndicators data={data} /></BarChart>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