React Chart Component Examples
Copy-paste React chart examples built on Recharts: bar, stacked bar, line, area, pie, donut, and a tab-switched interactive chart with themed tooltips.
Most React dashboards end up on Recharts, and most of them end up writing the same wrapper around it: a responsive container, a palette that respects dark mode, a tooltip that does not look like a browser default, and a legend that reads labels from somewhere sensible. Drivn's Chart is that wrapper, already written. You keep composing <BarChart>, <LineChart>, and <PieChart> from recharts; Drivn supplies the container and four dot-notation helpers — Chart.Grid, Chart.XAxis, Chart.Tooltip, and Chart.Legend.
Every example on this page shares one pattern. A config object maps each data key to a label and a color, typed with satisfies ChartConfig so a misspelled key fails at compile time. The root turns each colored entry into a scoped CSS variable, which is why the series below read fill="var(--color-desktop)" instead of a hex value. Colors point at the five --color-chart-* tokens the Drivn CLI appends to your globals, so every chart flips with the theme without extra code.
The snippets cover the chart types dashboards actually ship: grouped and stacked bars, trend lines, a filled area, pie and donut breakdowns, and a bar chart switched between series by a Tabs control. Each one is copy-paste ready against the installed source.
Bar chart with tooltip and legend
The baseline example is a grouped bar chart with two series. The data array holds one row per month, and config gives each series a display label and a token color. Inside <Chart>, the four helpers do the presentation work: Chart.Grid draws horizontal guide lines only, Chart.XAxis prints the month labels without tick marks or a baseline, Chart.Legend renders a swatch and label per series at the bottom, and Chart.Tooltip shows a themed panel on hover with the cursor band switched off.
The tooltip reads labels from your config, so the panel says "Desktop" rather than the raw desktop key, and numeric values are formatted with toLocaleString() in a monospaced, tabular font so digits align. The container defaults to w-full aspect-video min-h-[200px]; pass a className such as aspect-square or h-64 to resize it. Wrap the chart in a Card to give it a title and a border in a dashboard grid.
1 import { Chart, type ChartConfig } from "@/components/ui/chart" 2 import { Bar, BarChart } from "recharts" 3 4 const data = [ 5 { month: "Jan", desktop: 186, mobile: 80 }, 6 { month: "Feb", desktop: 305, mobile: 200 }, 7 { month: "Mar", desktop: 237, mobile: 120 }, 8 { month: "Apr", desktop: 73, mobile: 190 }, 9 { month: "May", desktop: 209, mobile: 130 }, 10 { month: "Jun", desktop: 214, mobile: 140 }, 11 ] 12 13 const config = { 14 desktop: { label: "Desktop", color: "var(--color-chart-1)" }, 15 mobile: { label: "Mobile", color: "var(--color-chart-3)" }, 16 } satisfies ChartConfig 17 18 export default function Page() { 19 return ( 20 <Chart config={config}> 21 <BarChart data={data}> 22 <Chart.Grid /> 23 <Chart.XAxis dataKey="month" /> 24 <Chart.Legend /> 25 <Chart.Tooltip /> 26 <Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} /> 27 <Bar dataKey="mobile" fill="var(--color-mobile)" radius={4} /> 28 </BarChart> 29 </Chart> 30 ) 31 }
Stacked bar chart
Give both <Bar> elements the same stackId and Recharts draws them on top of each other instead of side by side. Stacked bars answer a different question from grouped ones: the total height shows the combined value per month, and each segment shows its share. Use them for traffic by device, revenue by plan, or any breakdown where the sum matters as much as the parts.
The only styling detail is the corner radius. A uniform radius={4} would round the seam between segments, so the bottom series gets no radius and the top series uses radius={[4, 4, 0, 0]} — top-left, top-right, bottom-right, bottom-left — so only the outer edge of the stack is rounded. The tooltip lists both series for the hovered month, which is usually enough without a separate total row. The data and config objects are the same ones used in the bar example above.
1 <Chart config={config}> 2 <BarChart data={data}> 3 <Chart.Grid /> 4 <Chart.XAxis dataKey="month" /> 5 <Chart.Legend /> 6 <Chart.Tooltip /> 7 <Bar dataKey="desktop" stackId="a" fill="var(--color-desktop)" /> 8 <Bar 9 dataKey="mobile" 10 stackId="a" 11 fill="var(--color-mobile)" 12 radius={[4, 4, 0, 0]} 13 /> 14 </BarChart> 15 </Chart>
Line chart with line indicators
Switch to LineChart and Line when the reader cares about direction over time more than individual values. type="monotone" smooths the curve without overshooting data points, strokeWidth={2} keeps the line legible at small sizes, and dot={false} removes the point markers that clutter a six-month trend.
The one change on the Drivn side is the tooltip indicator. Passing content={<Chart.TooltipContent indicator="line" />} to Chart.Tooltip replaces the square swatch beside each series with a thin vertical bar, which visually matches a line series better than a block of color. Because Chart.Tooltip spreads your props after its defaults, supplying content is all it takes — the cursor stays off. The same override works for every chart type, and the Chart props reference lists both indicator values.
1 <Chart config={config}> 2 <LineChart data={data}> 3 <Chart.Grid /> 4 <Chart.XAxis dataKey="month" /> 5 <Chart.Legend /> 6 <Chart.Tooltip content={<Chart.TooltipContent indicator="line" />} /> 7 <Line 8 type="monotone" 9 dataKey="desktop" 10 stroke="var(--color-desktop)" 11 strokeWidth={2} 12 dot={false} 13 /> 14 <Line 15 type="monotone" 16 dataKey="mobile" 17 stroke="var(--color-mobile)" 18 strokeWidth={2} 19 dot={false} 20 /> 21 </LineChart> 22 </Chart>
Area chart
An area chart is a line chart with the space underneath filled in, which gives a single metric more visual weight on a dashboard overview. Set both stroke and fill to the same config variable and lower fillOpacity to 0.2 so the grid lines stay visible through the fill. This example plots one series and leaves out the legend, since a single area labelled by the surrounding card title does not need one.
Because the color comes from var(--color-desktop) and that variable resolves to a chart token, the fill and stroke both switch with the theme — a near-black area on the light theme becomes a near-white one on dark. For a multi-series area chart, add a second <Area> with its own key and consider a stackId so the layers do not hide each other. Pair it with a Skeleton placeholder while the data loads.
1 <Chart config={config}> 2 <AreaChart data={data}> 3 <Chart.Grid /> 4 <Chart.XAxis dataKey="month" /> 5 <Chart.Tooltip /> 6 <Area 7 type="monotone" 8 dataKey="desktop" 9 stroke="var(--color-desktop)" 10 fill="var(--color-desktop)" 11 fillOpacity={0.2} 12 /> 13 </AreaChart> 14 </Chart>
Pie and donut charts
Pie charts flip the data model: each row is a slice, so the color lives on the row as fill="var(--color-chrome)" and the config maps every browser value to a label and one of the five chart tokens. Set nameKey="browser" on <Pie> so the tooltip and legend look labels up by browser name. Pass content={<Chart.TooltipContent hideLabel />} to drop the heading, since a pie slice has no axis label to show.
For a donut, add innerRadius={60} and render two Recharts <Label> children inside the <Pie> — one for the total, one for its caption. The labels take Tailwind classes such as fill-foreground and fill-muted-foreground, so the center text follows the theme like the rest of the chart. strokeWidth={5} opens a gap between slices; the container already makes sector strokes transparent through [&_.recharts-sector]:stroke-transparent in its root styles.
1 const browsers = [ 2 { browser: "chrome", visitors: 275, fill: "var(--color-chrome)" }, 3 { browser: "safari", visitors: 200, fill: "var(--color-safari)" }, 4 { browser: "firefox", visitors: 187, fill: "var(--color-firefox)" }, 5 { browser: "edge", visitors: 173, fill: "var(--color-edge)" }, 6 { browser: "other", visitors: 90, fill: "var(--color-other)" }, 7 ] 8 9 const browserConfig = { 10 chrome: { label: "Chrome", color: "var(--color-chart-1)" }, 11 safari: { label: "Safari", color: "var(--color-chart-2)" }, 12 firefox: { label: "Firefox", color: "var(--color-chart-3)" }, 13 edge: { label: "Edge", color: "var(--color-chart-4)" }, 14 other: { label: "Other", color: "var(--color-chart-5)" }, 15 } satisfies ChartConfig 16 17 <Chart config={browserConfig}> 18 <PieChart> 19 <Chart.Tooltip content={<Chart.TooltipContent hideLabel />} /> 20 <Pie 21 data={browsers} 22 dataKey="visitors" 23 nameKey="browser" 24 innerRadius={60} 25 strokeWidth={5} 26 > 27 <Label 28 value="925" 29 position="centerBottom" 30 className="fill-foreground text-2xl font-semibold" 31 /> 32 <Label 33 value="Visitors" 34 position="centerTop" 35 dy={6} 36 className="fill-muted-foreground" 37 /> 38 </Pie> 39 </PieChart> 40 </Chart>
Interactive chart with Tabs
Dashboards often show one metric at a time with a switch to change it. Hold the active key in useState, render a compact Tabs list above the chart, and feed the key to a single <Bar> as both dataKey and the key inside the fill color variable. Because the config already defines --color-desktop and --color-mobile on the container, the bar recolors as soon as the tab changes, with no lookup table of its own.
The Tabs here are controlled through value and onChange and render only the tab list — there are no panels, because the chart itself is the content. Recharts animates the bar heights between series on each switch. The same pattern scales to time ranges: keep a range state, filter data before passing it to BarChart, and let the tabs choose between 7, 30, and 90 days.
1 import * as React from "react" 2 import { Chart, type ChartConfig } from "@/components/ui/chart" 3 import { Tabs } from "@/components/ui/tabs" 4 import { Bar, BarChart } from "recharts" 5 6 export default function Page() { 7 const [active, setActive] = React.useState("desktop") 8 return ( 9 <div> 10 <Tabs variant="compact" value={active} onChange={setActive}> 11 <Tabs.List> 12 <Tabs.Tab value="desktop">Desktop</Tabs.Tab> 13 <Tabs.Tab value="mobile">Mobile</Tabs.Tab> 14 </Tabs.List> 15 </Tabs> 16 <Chart config={config}> 17 <BarChart data={data}> 18 <Chart.Grid /> 19 <Chart.XAxis dataKey="month" /> 20 <Chart.Tooltip /> 21 <Bar dataKey={active} fill={`var(--color-${active})`} radius={4} /> 22 </BarChart> 23 </Chart> 24 </div> 25 ) 26 }
Install Drivn in one command
Copy the source into your project and own every line. Zero runtime dependencies, pure React + Tailwind.
npx drivn@latest createRequires Node 18+. Works with npm, pnpm, and yarn.
Frequently asked questions
It writes chart.tsx into your components folder, installs recharts as the single npm dependency, and appends the five chart color tokens to your globals stylesheet. If your globals file already defines --chart-1, the token step is skipped so your existing palette is left alone. Nothing else is added to your bundle.
Edit the --chart-1 through --chart-5 values in your globals file to recolor every chart at once, under both :root and [data-theme="dark"]. For a one-off series, set its config color to any CSS color or custom property. The component only reads the resolved value, so brand palettes and per-chart overrides both work.
Yes. Drivn wraps only the X axis because most dashboard charts hide the Y axis and rely on the tooltip for exact values. Import YAxis from recharts and place it inside the chart next to Chart.XAxis. The container styles already color axis lines with stroke-border and tick text with fill-muted-foreground, so it matches without extra classes.
Because satisfies checks the object against ChartConfig while keeping its literal keys. An annotation like const config: ChartConfig widens the keys to string, so you lose autocomplete on config.desktop. With satisfies, a typo in an entry still fails type-checking and the exact key names stay available to the rest of the file.
The chart file is marked 'use client', since Recharts measures the container and handles pointer events in the browser. Fetch your data in a Server Component and pass the rows down as a prop; Next.js renders the chart on the client and keeps the data fetching on the server, with no extra wrapper needed.