Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Chart examples · Bar

A stacked bar chart with a legend for React

A bar chart stacking desktop and mobile visitors for each month, with a legend.

Framework
UI library

Use it to show each month's total and what it's made of. Desktop and mobile are stacked in one bar per month, the corners are rounded only on the outer ends, and a legend names both series.

Preview

Preview width

Installation

Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.

FAQ

How do the bars stack?

Both Bar components set stackId="a". Desktop is first, so it sits on the baseline. Mobile is second, so it sits on top. The top of the mobile segment is that month's total. Each chartData row has desktop and mobile.

Why are the rounded corners split across the two bars?

Desktop sets radius={[0, 0, 4, 4]}, the bottom two corners. Mobile sets radius={[4, 4, 0, 0]}, the top two corners. The corners that meet in the middle stay square. Fills are var(--color-desktop) and var(--color-mobile).

How does the legend get its labels?

ChartLegend sets content to ChartLegendContent, which lists Desktop and Mobile from config, each with a color swatch. This file passes no onClick. verticalAlign stays at the default, bottom, which adds space above the legend.

What does the tooltip show?

ChartTooltipContent sets hideLabel, so the month isn't repeated in the title. The rows are Desktop and Mobile with their values. This ChartTooltip doesn't set cursor={false}, so the hovered bar keeps the default cursor.

How are the month ticks shortened?

XAxis uses dataKey="month" and tickFormatter={formatMonth}, which keeps value.slice(0, 3). axisLine and tickLine are false, and tickMargin is 10. CartesianGrid sets vertical={false}.

Can I move across the bars with the keyboard?

Yes. BarChart sets accessibilityLayer, so the bars can take focus. The month tick and the labels in config name each stack. ChartContainer keeps the default 16:9 box inside a w-full max-w-xl frame.