Skip to main content

Chart

Beautiful, accessible charts built on Recharts and themed by your design system.

On this page
MonthDesktopMobile
January18680
February305200
March237120
April73190
May209130
June214140
const chartData = /* ... */;
const chartConfig = /* ... */;

<>
  <ChartContainer config={chartConfig} className="min-h-[200px] w-full">
    <BarChart accessibilityLayer data={chartData}>
      <CartesianGrid vertical={false} />
      <XAxis
        dataKey="month"
        tickLine={false}
        tickMargin={10}
        axisLine={false}
        tickFormatter={(value) => value.slice(0, 3)}
      />
      <ChartTooltip
        cursor={false}
        content={<ChartTooltipContent indicator="dashed" />}
      />
      <ChartLegend content={<ChartLegendContent />} />
      <Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
      <Bar dataKey="mobile" fill="var(--color-mobile)" radius={4} />
    </BarChart>
  </ChartContainer>
  <ChartDataTable data={chartData} config={chartConfig} labelKey="month" />
</>

Charts are a thin, themeable layer over Recharts. You write a chart with Recharts' own components — BarChart, Bar, XAxis, and the rest — and wrap them in ChartContainer, which maps your series to your design system's colors, handles light and dark theming, and makes the chart responsive. The tooltip, legend, and a visually-hidden data table are styled to match the rest of your components, so a chart looks at home next to a card or a button with no extra work.

Use the primitives directly to build any chart Recharts supports, or install a ready-made family and copy the variant you need. Browse every variant on the charts page.

Installation

The primitives — ChartContainer, ChartTooltip, ChartLegend, their *Content variants, and ChartDataTable — ship as a single chart item:

npx shadcn@latest add @dotui/chart

Each family — bar, line, area, pie, radar, and radial — ships as its own item with a curated set of variants, and pulls in chart and card automatically:

npx shadcn@latest add @dotui/chart-bar

You only need to add the chart item directly when you are composing a chart by hand. Installing any family brings the primitives along with it.

Usage

Import the primitives you need alongside the Recharts components for your chart type:

import { Bar, BarChart, CartesianGrid, XAxis } from 'recharts'

import {
  type ChartConfig,
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
} from '@/components/ui/chart'

A chart is built from three pieces: your data (an array of rows), a config that describes each series, and the Recharts chart wrapped in ChartContainer.

const chartData = [
  { month: 'January', desktop: 186 },
  { month: 'February', desktop: 305 },
  { month: 'March', desktop: 237 },
]

const chartConfig = {
  desktop: { label: 'Desktop', color: 'var(--chart-1)' },
} satisfies ChartConfig

export function Example() {
  return (
    <ChartContainer config={chartConfig} className="min-h-[200px] w-full">
      <BarChart accessibilityLayer data={chartData}>
        <CartesianGrid vertical={false} />
        <XAxis dataKey="month" tickLine={false} axisLine={false} />
        <ChartTooltip content={<ChartTooltipContent />} />
        <Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
      </BarChart>
    </ChartContainer>
  )
}

ChartContainer reads chartConfig and exposes each series key as a CSS variable — the desktop key becomes var(--color-desktop), which the Bar references with its fill. This name-keyed indirection is the heart of the API: you assign a color once in config, and every Recharts element, the tooltip, and the legend pick it up by name. There is no color array to keep aligned with your data.

Chart config

config maps each series key to a label, a color (or a per-theme theme), and an optional icon:

const chartConfig = {
  desktop: { label: 'Desktop', color: 'var(--chart-1)' },
  mobile: { label: 'Mobile', color: 'var(--chart-2)' },
} satisfies ChartConfig

ChartContainer turns each entry into a --color-<key> CSS variable you reference from Recharts (fill="var(--color-desktop)"), and the tooltip and legend read it for labels and icons. Use satisfies ChartConfig rather than a type annotation so TypeScript keeps the exact keys, which makes the matching var(--color-<key>) names easy to keep in sync.

Because config is separate from data, a key with no series of its own — an axis category, for example — can still carry a label and a color, which is how per-category coloring on pie and radial charts works.

Theming

Series colors come from a categorical palette of five slots, --chart-1 through --chart-5. Your design system derives them from its theme hues, so charts stay on-brand and adapt to light and dark automatically — no per-mode values to maintain. The palette is editable under Chart colors in the editor, and updates live as you tweak it on the charts page.

Point each series at a slot through its config color:

const chartConfig = {
  desktop: { label: 'Desktop', color: 'var(--chart-1)' },
  mobile: { label: 'Mobile', color: 'var(--chart-2)' },
} satisfies ChartConfig

A color can be any CSS value, so you are not limited to the palette. To set a different color per mode, use theme instead of color:

const chartConfig = {
  desktop: { label: 'Desktop', theme: { light: '#2563eb', dark: '#60a5fa' } },
} satisfies ChartConfig

For per-category colors — common on pie and radial charts — give each row its own fill using the same var(--color-<key>) names:

const chartData = [
  { browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
  { browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
]

Tooltip and legend

ChartTooltip and ChartLegend are the Recharts primitives; ChartTooltipContent and ChartLegendContent are the styled, config-aware contents you pass to them. Both resolve labels, colors, and icons from your config, so they stay consistent with the chart without extra wiring:

<ChartTooltip content={<ChartTooltipContent indicator="line" />} />
<ChartLegend content={<ChartLegendContent />} />

ChartTooltipContent accepts an indicator of dot, line, or dashed to change the marker next to each value, plus hideLabel and hideIndicator to trim it down. ChartLegendContent accepts hideIcon and a nameKey for reading labels from a different config key. See the API reference for the full set of props.

Accessibility

Charts encode data with color and position, which is invisible to assistive technology, so accessibility is handled in two layers.

First, pass accessibilityLayer to the Recharts chart. It enables keyboard navigation and screen-reader announcements as the user moves across data points:

<BarChart accessibilityLayer data={chartData}>

Second — and unique to dotUI — every family demo renders ChartDataTable alongside the chart: a visually-hidden <table> derived from the same data and config. It exposes the underlying figures to screen readers and other assistive tools without affecting the visual layout, giving you a real data-table fallback for free:

<ChartDataTable data={chartData} config={chartConfig} labelKey="month" />

labelKey names the field used for each row's header — the x-axis category on cartesian charts, or the slice name on pie and radial charts. ChartDataTable adapts to your data's shape on its own: one column per series for bar, line, area, and radar; a two-column category/value table for pie and radial. Pass it the same data and config you gave ChartContainer and it stays in sync.

Families

Each family is a curated set of variants — install one, then copy the variant you need. Browse them all on the charts page.

Line

MonthDesktopMobile
January18680
February305200
March237120
April73190
May209130
June214140

Area

MonthDesktopMobile
January18680
February305200
March237120
April73190
May209130
June214140

Pie

BrowserVisitors
Chrome275
Safari200
Firefox187
Edge173
Other90

Radar

MonthDesktop
January186
February305
March237
April273
May209
June214

Radial

MonthDesktopMobile
january1,260570

Bar

MonthDesktop
January186
February305
March237
April73
May209
June214

API Reference

ChartContainer

Wraps a Recharts chart with theming and a responsive container. Pass your `config` (series → label / color / icon) and a single Recharts chart child.

Supports all div attributes.

PropType
ChartConfig
{ width: number; height: number; }

ChartTooltipContent

Styled content for a chart tooltip. Use inside `<ChartTooltip content={...} />`.

Supports all div attributes.

PropType
"dashed" | "dot" | "line"
boolean
boolean
string
string

ChartLegendContent

Styled content for a chart legend. Use inside `<ChartLegend content={...} />`.

Supports all div attributes.

PropType
boolean
string
"bottom" | "top"

ChartDataTable

A visually-hidden table that mirrors a chart's series for assistive tech (dotUI accessibility layer; not part of shadcn). Render it alongside any chart with the same props you already pass. It adapts to the data shape: wide-format (bar/line/area/radar) gets one column per series; long-format (pie/radial) gets a two-column category/value table.

Supports all table attributes.

PropType
Record<string, unknown>[]
ChartConfig
string
string
string

Last updated on 6/27/2026