Skip to content
Drivn
6 min read

How to Add a Chart to a React App

Step-by-step guide to adding a copy-and-own Chart to React with the Drivn CLI — recharts bar, line, area, and pie charts with typed config and tooltips.

Adding a chart to a React app usually means picking between two compromises: a fully styled charting package whose tooltips and colors never quite match your design system, or raw recharts, where every chart repeats the same grid, axis, and tooltip setup. Drivn's Chart sits between them. It keeps recharts as the drawing engine and adds a thin, typed layer you own: one config object that names and colors each series, plus dot-notation pieces — Chart.Grid, Chart.XAxis, Chart.Tooltip, Chart.Legend — with Drivn defaults already applied.

Those defaults are deliberately quiet. The grid draws horizontal lines only, the x-axis drops its tick marks and baseline, the tooltip turns off the hover cursor, and the legend sits below the plot. Tooltip and legend text come from your config labels, so a series stored as desktop reads “Desktop” without a formatter function. Colors resolve through CSS variables, so light and dark mode work without a single conditional in the chart code.

This tutorial takes an existing React project from nothing to a working bar chart, then adds tooltip and legend options, legend icons, and line, area, and pie variants. It applies equally to Vite + React and Next.js; for App Router data loading, see the Next.js Chart guide.

Prerequisites

Drivn assumes three things in your React project: Tailwind CSS v4 processing your stylesheets, TypeScript configured (the component ships as a .tsx file with typed config and props), and a @/ path alias pointing at your source directory. Projects created with npx drivn@latest create have all three, plus the drivn.config.json the CLI reads to find your components folder and globals stylesheet. If you started from create-next-app or npm create vite, run npx drivn@latest create inside the project once before adding components — the Chart install step needs that config to know where to append its color tokens. The installation page lists the minimal setup for each starter. You do not need to install recharts yourself; the CLI handles it.

Step 1 — Install the Chart with the CLI

Run npx drivn add chart from the project root. The CLI writes chart.tsx into your components directory, installs recharts with whichever package manager it detects from your lockfile, and appends a block of chart tokens to your globals stylesheet: --chart-1 through --chart-5 for light mode, an inverted ramp under [data-theme="dark"], and --color-chart-* aliases inside @theme inline. If those tokens already exist, the step is skipped with a warning instead of duplicating CSS. Nothing else is added — no provider to mount, no global config object, no runtime UI dependency beyond recharts itself. The installed file is yours to edit like any other component; the CLI docs describe the flags for custom install paths.

1# add the Chart to your existing React project
2npx drivn add chart

Step 2 — Describe your series with ChartConfig

Every Drivn chart starts with a config object keyed by the series names in your data. Each entry can hold a label (any ReactNode, shown in the tooltip and legend), a color (any CSS color, usually one of the var(--color-chart-N) tokens), and an optional icon component for the legend. The Chart root reads this object and sets a CSS variable per colored key on its wrapper — desktop becomes --color-desktop, mobile becomes --color-mobile — so the series elements you render in the next step reference a variable instead of a hard-coded value. Writing the object with satisfies ChartConfig gives you autocomplete on the field names while keeping the literal keys intact for TypeScript. The Chart docs list every config field.

1import { type ChartConfig } from '@/components/ui/chart'
2
3export const data = [
4 { month: 'Jan', desktop: 186, mobile: 80 },
5 { month: 'Feb', desktop: 305, mobile: 200 },
6 { month: 'Mar', desktop: 237, mobile: 120 },
7 { month: 'Apr', desktop: 73, mobile: 190 },
8]
9
10export const config = {
11 desktop: { label: 'Desktop', color: 'var(--color-chart-1)' },
12 mobile: { label: 'Mobile', color: 'var(--color-chart-3)' },
13} satisfies ChartConfig

Step 3 — Render a bar chart

Wrap one recharts chart element in <Chart config={config}>. The root renders a full-width wrapper at a 16:9 aspect-video ratio with a 200 pixel minimum height, places your chart inside recharts' ResponsiveContainer, and provides the config through context. Inside the recharts element, mix Drivn pieces with plain recharts series: Chart.Grid and Chart.XAxis carry the quiet defaults, while Bar comes straight from recharts and points its fill at the variable the root created. Because the Chart file starts with 'use client', it works as-is in Vite and renders as a client component in a Next.js App Router project. To change the size, pass className="aspect-auto h-64" — the root merges classes through cn. More layouts live on the React Chart examples page.

1import { Bar, BarChart } from 'recharts'
2import { Chart } from '@/components/ui/chart'
3import { config, data } from '@/components/traffic-data'
4
5export function TrafficChart() {
6 return (
7 <Chart config={config}>
8 <BarChart data={data}>
9 <Chart.Grid />
10 <Chart.XAxis dataKey="month" />
11 <Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
12 <Bar dataKey="mobile" fill="var(--color-mobile)" radius={4} />
13 </BarChart>
14 </Chart>
15 )
16}

Step 4 — Add a tooltip, legend, and icons

Drop Chart.Tooltip and Chart.Legend inside the recharts element. The tooltip renders Chart.TooltipContent on a bg-card panel with a border and shadow: the axis label as a heading, then one row per series with a color indicator, the config label, and the value formatted with toLocaleString(). Pass content={<Chart.TooltipContent indicator="line" />} for a thin bar instead of a dot, or hideLabel to drop the heading. The legend defaults to the bottom of the plot; set verticalAlign="top" to move it. When a config entry has an icon, the legend renders that component in place of the color swatch — pass the component itself, such as Monitor from lucide-react, not a JSX element. For styling details, compare with Drivn vs shadcn/ui Chart.

1import { Monitor, Smartphone } from 'lucide-react'
2import { type ChartConfig } from '@/components/ui/chart'
3
4export const config = {
5 desktop: {
6 label: 'Desktop',
7 icon: Monitor,
8 color: 'var(--color-chart-1)',
9 },
10 mobile: {
11 label: 'Mobile',
12 icon: Smartphone,
13 color: 'var(--color-chart-3)',
14 },
15} satisfies ChartConfig
16
17// inside <BarChart data={data}>
18<Chart.Tooltip content={<Chart.TooltipContent indicator="line" />} />
19<Chart.Legend verticalAlign="top" />

Step 5 — Switch to line, area, or pie

Changing the chart type is a matter of swapping recharts primitives; the Chart wrapper and config stay the same. For a trend line, replace BarChart and Bar with LineChart and Line, setting stroke to the series variable. An area chart works the same way with AreaChart and Area, using a low fillOpacity so grid lines show through. Pie and donut charts are the one structural change: they have no axes, so leave out Chart.Grid and Chart.XAxis, give each data row its own fill such as var(--color-chrome), and set nameKey so the tooltip and legend look up labels by slice name. Adding innerRadius to the Pie turns it into a donut. Each variant is shown in full in the Chart examples.

1import { Line, LineChart } from 'recharts'
2import { Chart } from '@/components/ui/chart'
3import { config, data } from '@/components/traffic-data'
4
5export function TrafficTrend() {
6 return (
7 <Chart config={config}>
8 <LineChart data={data}>
9 <Chart.Grid />
10 <Chart.XAxis dataKey="month" />
11 <Chart.Tooltip />
12 <Line
13 type="monotone"
14 dataKey="desktop"
15 stroke="var(--color-desktop)"
16 strokeWidth={2}
17 dot={false}
18 />
19 </LineChart>
20 </Chart>
21 )
22}

What's next

With one chart working, the same config-and-wrapper pattern covers the rest of a dashboard. Read the Chart reference for every sub-component prop, including Chart.TooltipContent and Chart.LegendContent when you want to pass them explicitly. To let users switch series, pair the chart with the compact Tabs variant and feed the active key into dataKey — the interactive example on the examples page shows the full wiring. Frame each chart in a Card for consistent dashboard tiles, and adjust the --chart-* token values from Theming to bring the palette in line with your brand. If you are on the App Router, the Next.js Chart guide shows server-side data loading.

Get started

Install Drivn in one command

Copy the source into your project and own every line. Zero runtime dependencies, pure React + Tailwind.

Follow Drivn updates
New components, improvements, and guides every release.
Enjoying Drivn?
Star the repo on GitHub to follow new component releases.
Star →

Frequently asked questions

Yes. The Chart has no dependency on Next.js or any router — it needs React, Tailwind v4, TypeScript, and recharts, which the CLI installs for you. Initialize Drivn in the Vite project with npx drivn@latest create, then run npx drivn add chart. The 'use client' directive at the top of the file is ignored outside the App Router, so nothing changes.

Point each config entry's color at any CSS color. The five --color-chart-* tokens are the default palette, and editing their values in your globals stylesheet recolors every chart at once, in both light and dark mode. For a single series, set color to another token such as var(--color-primary), and the root exposes it as --color-{key} for your series to use.

Yes. Drivn only wraps the pieces that need house defaults — the grid, the x-axis, the tooltip, and the legend. Every other recharts primitive, including YAxis, ReferenceLine, Brush, and Cell, goes inside the chart element exactly as the recharts docs describe. The root styles axis ticks and grid lines with Drivn tokens through descendant selectors, so added axes match automatically.

Because Chart.LegendContent reads the config from context and looks up each legend item by its value or dataKey. When an entry has a label, the legend shows it; when it has an icon, the icon replaces the color swatch. Keys with no matching config entry fall back to the raw value, so a missing label is visible right away.