- Charts
- Line Chart
- Bar Chart
- Area Chart
- Scatter Chart
- Pie Chart
- Donut Chart
- Dot Plot Chart
- Lollipop Chart
- Dumbbell Chart
- Slope Chart
- Range Chart
- Histogram Chart
- Box Plot Chart
- Violin Chart
- Polar Chart
- Parallel Coordinates
- SPLOM Chart
- Parcats Chart
- Candlestick Chart
- OHLC Chart
- Waterfall Chart
- Funnel Chart
- Heatmap Chart
- Contour Chart
- Density Chart
- Ternary Chart
- Radar Chart
- Treemap Chart
- Sunburst Chart
- Sankey Chart
- Gauge Chart
- Bullet Chart
- Icicle Chart
- Network Graph
- Dendrogram
- Choropleth Chart
"use client"
import { BarChart } from "@/components/ui/charts"
// Page view data - 30 days of traffic
const chartData = [
186, 205, 237, 173, 209, 214, 278, 312, 245, 289, 234, 276, 198, 267, 289,
312, 256, 234, 289, 267, 298, 312, 278, 256, 234, 267, 289, 312, 334, 356,
].map((value, i) => ({
label: `${i + 1}`,
value,
}))
export function BarChartDemo() {
return (
<BarChart
data={chartData}
color="#2563eb"
showGrid
showTooltip
barRadius={0}
aspectRatio={2.5}
/>
)
}
About
The Bar Chart component is built on top of Recharts and provides a simple, declarative way to create bar charts. It supports various configurations including:
- Vertical and horizontal orientations
- Single and multiple data series
- Stacked and grouped bar layouts
- Custom tooltips with theme-aware styling
- Responsive design that adapts to container width
Installation
pnpm dlx shadcn@latest add https://ui.simplifying.ai/r/bar-chart.json
Usage
import { BarChart } from "@/components/ui/charts"
const data = [
{ label: "Jan", value: 4000 },
{ label: "Feb", value: 3000 },
{ label: "Mar", value: 5000 },
]
export function MyChart() {
return <BarChart data={data} />
}Examples
Default
The default bar chart displays categorical data with sharp-edged bars, horizontal grid lines, and an interactive tooltip on hover.
"use client"
import { BarChart } from "@/components/ui/charts"
// Page view data - 30 days of traffic
const chartData = [
186, 205, 237, 173, 209, 214, 278, 312, 245, 289, 234, 276, 198, 267, 289,
312, 256, 234, 289, 267, 298, 312, 278, 256, 234, 267, 289, 312, 334, 356,
].map((value, i) => ({
label: `${i + 1}`,
value,
}))
export function BarChartDemo() {
return (
<BarChart
data={chartData}
color="#2563eb"
showGrid
showTooltip
barRadius={0}
aspectRatio={2.5}
/>
)
}
With Labels
Use the showLabel prop to display values directly on top of each bar. This is useful when you want to show exact values without requiring users to hover.
"use client"
import {
Bar,
BarChart,
CartesianGrid,
LabelList,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from "recharts"
const chartData = [
{ month: "January", desktop: 186 },
{ month: "February", desktop: 305 },
{ month: "March", desktop: 237 },
{ month: "April", desktop: 73 },
{ month: "May", desktop: 209 },
{ month: "June", desktop: 214 },
]
export function BarChartLabelDemo() {
return (
<div className="w-full max-w-md">
<ResponsiveContainer width="100%" aspect={1.5}>
<BarChart
data={chartData}
margin={{
top: 30,
right: 10,
left: 10,
bottom: 40,
}}
>
<CartesianGrid
strokeDasharray="3 3"
vertical={false}
stroke="hsl(var(--border))"
strokeOpacity={0.5}
/>
<XAxis
dataKey="month"
axisLine={false}
tickLine={false}
tick={{ fontSize: 12 }}
tickFormatter={(value) => value.slice(0, 3)}
tickMargin={8}
/>
<YAxis hide />
<Tooltip
cursor={{ fill: "hsl(var(--muted-foreground))", opacity: 0.08 }}
content={({ active, payload, label }) => {
if (!active || !payload?.length) return null
return (
<div className="bg-background rounded-lg border px-3 py-2 shadow-lg">
<p className="text-foreground text-sm font-medium">{label}</p>
<p className="text-sm" style={{ color: "#2563eb" }}>
Desktop: {payload[0]?.value}
</p>
</div>
)
}}
/>
<Bar dataKey="desktop" fill="#2563eb" radius={8}>
<LabelList
dataKey="desktop"
position="top"
offset={12}
className="fill-foreground"
fontSize={12}
/>
</Bar>
</BarChart>
</ResponsiveContainer>
</div>
)
}
<BarChart data={data} showLabel labelPosition="top" />Horizontal
Horizontal bar charts are ideal for displaying data with long category names or when you have many categories. Use layout="vertical" to switch orientation (Recharts naming convention).
"use client"
import {
Bar,
BarChart,
CartesianGrid,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from "recharts"
const chartData = [
{ month: "January", desktop: 186 },
{ month: "February", desktop: 305 },
{ month: "March", desktop: 237 },
{ month: "April", desktop: 73 },
{ month: "May", desktop: 209 },
{ month: "June", desktop: 214 },
]
export function BarChartHorizontalDemo() {
return (
<div className="w-full max-w-md">
<ResponsiveContainer width="100%" aspect={1.5}>
<BarChart
data={chartData}
layout="vertical"
margin={{
top: 10,
right: 10,
left: 10,
bottom: 10,
}}
>
<CartesianGrid
strokeDasharray="3 3"
horizontal={false}
stroke="hsl(var(--border))"
strokeOpacity={0.5}
/>
<YAxis
dataKey="month"
type="category"
axisLine={false}
tickLine={false}
tick={{ fontSize: 12 }}
tickFormatter={(value) => value.slice(0, 3)}
width={40}
/>
<XAxis
type="number"
axisLine={false}
tickLine={false}
tick={{ fontSize: 12 }}
/>
<Tooltip
cursor={{ fill: "hsl(var(--muted-foreground))", opacity: 0.08 }}
content={({ active, payload, label }) => {
if (!active || !payload?.length) return null
return (
<div className="bg-background rounded-lg border px-3 py-2 shadow-lg">
<p className="text-foreground text-sm font-medium">{label}</p>
<p className="text-sm" style={{ color: "#2563eb" }}>
Desktop: {payload[0]?.value}
</p>
</div>
)
}}
/>
<Bar dataKey="desktop" fill="#2563eb" radius={4} />
</BarChart>
</ResponsiveContainer>
</div>
)
}
<BarChart data={data} layout="vertical" />Multiple / Grouped
Display multiple data series side-by-side to compare different metrics across categories. Use the MultiBarChart component with a series configuration.
"use client"
import {
Bar,
BarChart,
CartesianGrid,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from "recharts"
const chartData = [
{ month: "January", desktop: 186, mobile: 80 },
{ month: "February", desktop: 305, mobile: 200 },
{ month: "March", desktop: 237, mobile: 120 },
{ month: "April", desktop: 73, mobile: 190 },
{ month: "May", desktop: 209, mobile: 130 },
{ month: "June", desktop: 214, mobile: 140 },
]
export function BarChartMultipleDemo() {
return (
<div className="w-full max-w-md">
<ResponsiveContainer width="100%" aspect={1.5}>
<BarChart
data={chartData}
margin={{
top: 10,
right: 10,
left: 10,
bottom: 40,
}}
>
<CartesianGrid
strokeDasharray="3 3"
vertical={false}
stroke="hsl(var(--border))"
strokeOpacity={0.5}
/>
<XAxis
dataKey="month"
axisLine={false}
tickLine={false}
tick={{ fontSize: 12 }}
tickFormatter={(value) => value.slice(0, 3)}
tickMargin={8}
/>
<YAxis
axisLine={false}
tickLine={false}
tick={{ fontSize: 12 }}
width={36}
/>
<Tooltip
cursor={{ fill: "hsl(var(--muted-foreground))", opacity: 0.08 }}
content={({ active, payload, label }) => {
if (!active || !payload?.length) return null
return (
<div className="bg-background rounded-lg border px-3 py-2 shadow-lg">
<p className="text-foreground mb-1 text-sm font-medium">
{label}
</p>
{payload.map((entry, index) => (
<div
key={index}
className="flex items-center gap-2 text-sm"
>
<div
className="size-2 rounded-full"
style={{ backgroundColor: entry.color }}
/>
<span className="text-muted-foreground">
{entry.name}:
</span>
<span style={{ color: entry.color }}>{entry.value}</span>
</div>
))}
</div>
)
}}
/>
<Bar dataKey="desktop" fill="#2563eb" radius={4} />
<Bar dataKey="mobile" fill="#60a5fa" radius={4} />
</BarChart>
</ResponsiveContainer>
{/* Legend */}
<div className="mt-4 flex flex-wrap items-center justify-center gap-4">
<div className="flex items-center gap-2 text-sm">
<div className="size-3 rounded-sm bg-[#2563eb]" />
<span className="text-muted-foreground">Desktop</span>
</div>
<div className="flex items-center gap-2 text-sm">
<div className="size-3 rounded-sm bg-[#60a5fa]" />
<span className="text-muted-foreground">Mobile</span>
</div>
</div>
</div>
)
}
import { MultiBarChart } from "@/components/ui/charts"
const data = [
{ label: "Jan", desktop: 186, mobile: 80 },
{ label: "Feb", desktop: 305, mobile: 200 },
]
const series = [
{ name: "Desktop", dataKey: "desktop", color: "#2563eb" },
{ name: "Mobile", dataKey: "mobile", color: "#60a5fa" },
]
<MultiBarChart data={data} series={series} />Stacked
Stacked bar charts show the cumulative total of multiple series. Add a stackId to each series to group them into stacks.
"use client"
import {
Bar,
BarChart,
CartesianGrid,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from "recharts"
const chartData = [
{ month: "January", desktop: 186, mobile: 80 },
{ month: "February", desktop: 305, mobile: 200 },
{ month: "March", desktop: 237, mobile: 120 },
{ month: "April", desktop: 73, mobile: 190 },
{ month: "May", desktop: 209, mobile: 130 },
{ month: "June", desktop: 214, mobile: 140 },
]
export function BarChartStackedDemo() {
return (
<div className="w-full max-w-md">
<ResponsiveContainer width="100%" aspect={1.5}>
<BarChart
data={chartData}
margin={{
top: 10,
right: 10,
left: 10,
bottom: 40,
}}
>
<CartesianGrid
strokeDasharray="3 3"
vertical={false}
stroke="hsl(var(--border))"
strokeOpacity={0.5}
/>
<XAxis
dataKey="month"
axisLine={false}
tickLine={false}
tick={{ fontSize: 12 }}
tickFormatter={(value) => value.slice(0, 3)}
tickMargin={8}
/>
<YAxis
axisLine={false}
tickLine={false}
tick={{ fontSize: 12 }}
width={36}
/>
<Tooltip
cursor={{ fill: "hsl(var(--muted-foreground))", opacity: 0.08 }}
content={({ active, payload, label }) => {
if (!active || !payload?.length) return null
const total = payload.reduce(
(sum, entry) => sum + (entry.value as number),
0
)
return (
<div className="bg-background rounded-lg border px-3 py-2 shadow-lg">
<p className="text-foreground mb-1 text-sm font-medium">
{label}
</p>
{payload.map((entry, index) => (
<div
key={index}
className="flex items-center gap-2 text-sm"
>
<div
className="size-2 rounded-full"
style={{ backgroundColor: entry.color }}
/>
<span className="text-muted-foreground">
{entry.name}:
</span>
<span style={{ color: entry.color }}>{entry.value}</span>
</div>
))}
<div className="text-muted-foreground mt-1 border-t pt-1 text-sm">
Total: {total}
</div>
</div>
)
}}
/>
<Bar
dataKey="desktop"
fill="#2563eb"
stackId="stack"
radius={[0, 0, 4, 4]}
/>
<Bar
dataKey="mobile"
fill="#60a5fa"
stackId="stack"
radius={[4, 4, 0, 0]}
/>
</BarChart>
</ResponsiveContainer>
{/* Legend */}
<div className="mt-4 flex flex-wrap items-center justify-center gap-4">
<div className="flex items-center gap-2 text-sm">
<div className="size-3 rounded-sm bg-[#2563eb]" />
<span className="text-muted-foreground">Desktop</span>
</div>
<div className="flex items-center gap-2 text-sm">
<div className="size-3 rounded-sm bg-[#60a5fa]" />
<span className="text-muted-foreground">Mobile</span>
</div>
</div>
</div>
)
}
const series = [
{ name: "Desktop", dataKey: "desktop", color: "#2563eb", stackId: "stack" },
{ name: "Mobile", dataKey: "mobile", color: "#60a5fa", stackId: "stack" },
]
<MultiBarChart data={data} series={series} />Negative Values
Bar charts can display both positive and negative values. Bars automatically extend above or below the zero reference line.
"use client"
import {
Bar,
BarChart,
CartesianGrid,
Cell,
ReferenceLine,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from "recharts"
const chartData = [
{ month: "January", value: 186 },
{ month: "February", value: -125 },
{ month: "March", value: 237 },
{ month: "April", value: -73 },
{ month: "May", value: 209 },
{ month: "June", value: -156 },
]
export function BarChartNegativeDemo() {
return (
<div className="w-full max-w-md">
<ResponsiveContainer width="100%" aspect={1.5}>
<BarChart
data={chartData}
margin={{
top: 10,
right: 10,
left: 10,
bottom: 40,
}}
>
<CartesianGrid
strokeDasharray="3 3"
vertical={false}
stroke="hsl(var(--border))"
strokeOpacity={0.5}
/>
<XAxis
dataKey="month"
axisLine={false}
tickLine={false}
tick={{ fontSize: 12 }}
tickFormatter={(value) => value.slice(0, 3)}
tickMargin={8}
/>
<YAxis
axisLine={false}
tickLine={false}
tick={{ fontSize: 12 }}
width={40}
/>
<ReferenceLine y={0} stroke="hsl(var(--border))" strokeWidth={1} />
<Tooltip
cursor={{ fill: "hsl(var(--muted-foreground))", opacity: 0.08 }}
content={({ active, payload, label }) => {
if (!active || !payload?.length) return null
const value = payload[0]?.value as number
return (
<div className="bg-background rounded-lg border px-3 py-2 shadow-lg">
<p className="text-foreground text-sm font-medium">{label}</p>
<p
className="text-sm"
style={{ color: value >= 0 ? "#2563eb" : "#60a5fa" }}
>
Value: {value}
</p>
</div>
)
}}
/>
<Bar dataKey="value" radius={4}>
{chartData.map((entry, index) => (
<Cell
key={`cell-${index}`}
fill={entry.value >= 0 ? "#2563eb" : "#60a5fa"}
/>
))}
</Bar>
</BarChart>
</ResponsiveContainer>
</div>
)
}
Interactive
Create interactive charts with state-controlled data series. Users can toggle between different views of the data.
"use client"
import * as React from "react"
import {
Bar,
BarChart,
CartesianGrid,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from "recharts"
const chartData = [
{ date: "2024-04-01", desktop: 222, mobile: 150 },
{ date: "2024-04-02", desktop: 97, mobile: 180 },
{ date: "2024-04-03", desktop: 167, mobile: 120 },
{ date: "2024-04-04", desktop: 242, mobile: 260 },
{ date: "2024-04-05", desktop: 373, mobile: 290 },
{ date: "2024-04-06", desktop: 301, mobile: 340 },
{ date: "2024-04-07", desktop: 245, mobile: 180 },
{ date: "2024-04-08", desktop: 409, mobile: 320 },
{ date: "2024-04-09", desktop: 59, mobile: 110 },
{ date: "2024-04-10", desktop: 261, mobile: 190 },
{ date: "2024-04-11", desktop: 327, mobile: 350 },
{ date: "2024-04-12", desktop: 292, mobile: 210 },
{ date: "2024-04-13", desktop: 342, mobile: 380 },
{ date: "2024-04-14", desktop: 137, mobile: 220 },
{ date: "2024-04-15", desktop: 120, mobile: 170 },
{ date: "2024-04-16", desktop: 138, mobile: 190 },
{ date: "2024-04-17", desktop: 446, mobile: 360 },
{ date: "2024-04-18", desktop: 364, mobile: 410 },
{ date: "2024-04-19", desktop: 243, mobile: 180 },
{ date: "2024-04-20", desktop: 89, mobile: 150 },
]
export function BarChartInteractiveDemo() {
const [activeChart, setActiveChart] = React.useState<"desktop" | "mobile">(
"desktop"
)
const total = React.useMemo(
() => ({
desktop: chartData.reduce((acc, curr) => acc + curr.desktop, 0),
mobile: chartData.reduce((acc, curr) => acc + curr.mobile, 0),
}),
[]
)
return (
<div className="w-full">
{/* Header with toggles */}
<div className="flex">
<button
className={`flex flex-1 flex-col justify-center gap-1 border-b px-6 py-4 text-left transition-colors even:border-l sm:border-l sm:px-8 sm:py-6 ${
activeChart === "desktop" ? "bg-muted/50" : "hover:bg-muted/30"
}`}
onClick={() => setActiveChart("desktop")}
>
<span className="text-muted-foreground text-xs">Desktop</span>
<span className="text-foreground text-lg leading-none font-bold sm:text-3xl">
{total.desktop.toLocaleString()}
</span>
</button>
<button
className={`flex flex-1 flex-col justify-center gap-1 border-b px-6 py-4 text-left transition-colors even:border-l sm:border-l sm:px-8 sm:py-6 ${
activeChart === "mobile" ? "bg-muted/50" : "hover:bg-muted/30"
}`}
onClick={() => setActiveChart("mobile")}
>
<span className="text-muted-foreground text-xs">Mobile</span>
<span className="text-foreground text-lg leading-none font-bold sm:text-3xl">
{total.mobile.toLocaleString()}
</span>
</button>
</div>
{/* Chart */}
<div className="px-2 pt-4 sm:px-6 sm:pt-6">
<ResponsiveContainer width="100%" aspect={2.5}>
<BarChart
data={chartData}
margin={{
top: 10,
right: 10,
left: 10,
bottom: 40,
}}
>
<CartesianGrid
strokeDasharray="3 3"
vertical={false}
stroke="hsl(var(--border))"
strokeOpacity={0.5}
/>
<XAxis
dataKey="date"
axisLine={false}
tickLine={false}
tick={{ fontSize: 12 }}
tickFormatter={(value) => {
const date = new Date(value)
return date.toLocaleDateString("en-US", {
month: "short",
day: "numeric",
})
}}
tickMargin={8}
minTickGap={32}
/>
<YAxis hide />
<Tooltip
cursor={{ fill: "hsl(var(--muted-foreground))", opacity: 0.08 }}
content={({ active, payload, label }) => {
if (!active || !payload?.length) return null
const date = new Date(label)
return (
<div className="bg-background rounded-lg border px-3 py-2 shadow-lg">
<p className="text-foreground text-sm font-medium">
{date.toLocaleDateString("en-US", {
month: "short",
day: "numeric",
year: "numeric",
})}
</p>
<p
className="text-sm"
style={{
color:
activeChart === "desktop" ? "#2563eb" : "#60a5fa",
}}
>
{activeChart === "desktop" ? "Desktop" : "Mobile"}:{" "}
{payload[0]?.value}
</p>
</div>
)
}}
/>
<Bar
dataKey={activeChart}
fill={activeChart === "desktop" ? "#2563eb" : "#60a5fa"}
radius={[4, 4, 0, 0]}
/>
</BarChart>
</ResponsiveContainer>
</div>
</div>
)
}
Mixed (Bar + Line)
Combine bars with a line chart to show both absolute values and trends. Uses Recharts' ComposedChart component.
"use client"
import {
Bar,
CartesianGrid,
ComposedChart,
Line,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from "recharts"
const chartData = [
{ month: "January", desktop: 186, trend: 160 },
{ month: "February", desktop: 305, trend: 220 },
{ month: "March", desktop: 237, trend: 250 },
{ month: "April", desktop: 73, trend: 180 },
{ month: "May", desktop: 209, trend: 200 },
{ month: "June", desktop: 214, trend: 230 },
]
export function BarChartMixedDemo() {
return (
<div className="w-full max-w-md">
<ResponsiveContainer width="100%" aspect={1.5}>
<ComposedChart
data={chartData}
margin={{
top: 10,
right: 10,
left: 10,
bottom: 40,
}}
>
<CartesianGrid
strokeDasharray="3 3"
vertical={false}
stroke="hsl(var(--border))"
strokeOpacity={0.5}
/>
<XAxis
dataKey="month"
axisLine={false}
tickLine={false}
tick={{ fontSize: 12 }}
tickFormatter={(value) => value.slice(0, 3)}
tickMargin={8}
/>
<YAxis
axisLine={false}
tickLine={false}
tick={{ fontSize: 12 }}
width={36}
/>
<Tooltip
cursor={{ fill: "hsl(var(--muted-foreground))", opacity: 0.08 }}
content={({ active, payload, label }) => {
if (!active || !payload?.length) return null
return (
<div className="bg-background rounded-lg border px-3 py-2 shadow-lg">
<p className="text-foreground mb-1 text-sm font-medium">
{label}
</p>
{payload.map((entry, index) => (
<div
key={index}
className="flex items-center gap-2 text-sm"
>
<div
className="size-2 rounded-full"
style={{ backgroundColor: entry.color }}
/>
<span className="text-muted-foreground">
{entry.name}:
</span>
<span style={{ color: entry.color }}>{entry.value}</span>
</div>
))}
</div>
)
}}
/>
<Bar dataKey="desktop" name="Desktop" fill="#2563eb" radius={4} />
<Line
type="monotone"
dataKey="trend"
name="Trend"
stroke="#60a5fa"
strokeWidth={2}
dot={{ r: 4, fill: "#60a5fa" }}
activeDot={{ r: 6, fill: "#60a5fa" }}
/>
</ComposedChart>
</ResponsiveContainer>
{/* Legend */}
<div className="mt-4 flex flex-wrap items-center justify-center gap-4">
<div className="flex items-center gap-2 text-sm">
<div className="size-3 rounded-sm bg-[#2563eb]" />
<span className="text-muted-foreground">Desktop</span>
</div>
<div className="flex items-center gap-2 text-sm">
<div className="h-0.5 w-3 rounded-full bg-[#60a5fa]" />
<span className="text-muted-foreground">Trend</span>
</div>
</div>
</div>
)
}
Active Bar
Highlight a specific bar using a custom shape with a dashed border effect. Useful for emphasizing a selected or current data point.
"use client"
import {
Bar,
BarChart,
Rectangle,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from "recharts"
const chartData = [
{ month: "January", sales: 187, fill: "#93c5fd" },
{ month: "February", sales: 200, fill: "#3b82f6" },
{ month: "March", sales: 275, fill: "#2563eb" },
{ month: "April", sales: 173, fill: "#1d4ed8" },
{ month: "May", sales: 209, fill: "#1e40af" },
]
// Index of the active (highlighted) bar
const ACTIVE_INDEX = 2
interface BarShapeProps {
x?: number
y?: number
width?: number
height?: number
fill?: string
index?: number
payload?: { fill: string }
radius?: number | [number, number, number, number]
[key: string]: unknown
}
export function BarChartActiveDemo() {
return (
<div className="w-full max-w-md">
<ResponsiveContainer width="100%" aspect={1.5}>
<BarChart
data={chartData}
margin={{
top: 10,
right: 10,
left: 10,
bottom: 40,
}}
>
<XAxis
dataKey="month"
axisLine={false}
tickLine={false}
tick={{ fontSize: 12 }}
tickFormatter={(value) => value.slice(0, 3)}
tickMargin={10}
/>
<YAxis hide />
<Tooltip
cursor={false}
content={({ active, payload }) => {
if (!active || !payload?.length) return null
const data = payload[0]
return (
<div className="bg-background flex items-center gap-2 rounded-lg border px-3 py-2 shadow-lg">
<div
className="size-3 rounded-sm"
style={{ backgroundColor: data.payload?.fill }}
/>
<span className="text-muted-foreground text-sm">Sales</span>
<span className="text-foreground text-sm font-medium">
{data.value}
</span>
</div>
)
}}
/>
<Bar
dataKey="sales"
radius={12}
shape={(props: unknown) => {
const { index, fill, ...rest } = props as BarShapeProps
return index === ACTIVE_INDEX ? (
<Rectangle
{...rest}
fill={fill}
fillOpacity={0.6}
stroke={fill}
strokeWidth={2}
strokeDasharray="4 4"
/>
) : (
<Rectangle {...rest} fill={fill} />
)
}}
/>
</BarChart>
</ResponsiveContainer>
</div>
)
}
import { Bar, BarChart, Rectangle } from "recharts"
const ACTIVE_INDEX = 2
<Bar
dataKey="sales"
radius={12}
shape={({ index, fill, ...props }) =>
index === ACTIVE_INDEX ? (
<Rectangle
{...props}
fill={fill}
fillOpacity={0.6}
stroke={fill}
strokeWidth={2}
strokeDasharray="4 4"
/>
) : (
<Rectangle {...props} fill={fill} />
)
}
/>API Reference
BarChart
| Prop | Type | Default | Description |
|---|---|---|---|
data | BarChartDataPoint[] | required | Array of data points to display |
color | string | "#2563eb" | Fill color for bars |
className | string | - | Additional CSS classes |
showGrid | boolean | true | Show horizontal grid lines |
showTooltip | boolean | true | Enable tooltip on hover |
showLabel | boolean | false | Show value labels on bars |
labelPosition | "top" | "center" | "bottom" | "inside" | "top" | Position of value labels |
valueFormatter | (value: number) => string | - | Format displayed values |
labelFormatter | (label: string) => string | - | Format category labels |
layout | "vertical" | "horizontal" | "horizontal" | Bar orientation (vertical = horizontal bars) |
barRadius | number | 4 | Corner radius of bars |
aspectRatio | number | 2 | Width to height ratio |
yAxisWidth | number | 48 | Width reserved for Y-axis labels |
MultiBarChart
| Prop | Type | Default | Description |
|---|---|---|---|
data | MultiBarChartDataPoint[] | required | Array of data points |
series | MultiBarChartSeries[] | required | Configuration for each data series |
className | string | - | Additional CSS classes |
showGrid | boolean | true | Show horizontal grid lines |
showTooltip | boolean | true | Enable tooltip on hover |
showLegend | boolean | true | Show legend below chart |
valueFormatter | (value: number) => string | - | Format displayed values |
labelFormatter | (label: string) => string | - | Format category labels |
layout | "vertical" | "horizontal" | "horizontal" | Bar orientation |
barRadius | number | 4 | Corner radius of bars |
aspectRatio | number | 2 | Width to height ratio |
yAxisWidth | number | 48 | Width reserved for Y-axis labels |
Data Types
// Single series data point
interface BarChartDataPoint {
label: string // Category name (e.g., "January")
value: number // Numeric value
fill?: string // Optional: override color for this bar
}
// Multiple series data point
interface MultiBarChartDataPoint {
label: string // Category name
[key: string]: string | number // Dynamic keys for each series
}
// Series configuration
interface MultiBarChartSeries {
name: string // Display name in tooltip/legend
dataKey: string // Key in data object
color: string // Bar fill color
stackId?: string // Optional: group into stack
}Customization
Custom Colors
Pass a color prop or use per-bar colors via the fill property in data:
const data = [
{ label: "Success", value: 80, fill: "#22c55e" },
{ label: "Warning", value: 15, fill: "#eab308" },
{ label: "Error", value: 5, fill: "#ef4444" },
]
<BarChart data={data} />Custom Tooltip
For advanced tooltip customization, use the Recharts components directly:
import { Bar, BarChart, Tooltip } from "recharts"
;<BarChart data={data}>
<Tooltip
content={({ active, payload }) => (
<div className="custom-tooltip">{/* Your custom content */}</div>
)}
/>
<Bar dataKey="value" />
</BarChart>Accessibility
- Charts include proper ARIA labels
- Tooltips are keyboard accessible
- Color schemes maintain sufficient contrast
- Grid lines help users track values across the chart
Notes
- Bar charts are best suited for comparing categorical data across different groups
- Use horizontal layout (
layout="vertical") when dealing with long category labels - Stacked bar charts are ideal for showing part-to-whole relationships over categories
- The
MultiBarChartcomponent automatically handles legend generation and color coordination - For time-series data with many points, consider using a line or area chart instead
- Bar radius can be adjusted for different visual styles (sharp edges vs rounded corners)