Data
Chart
A chart drawn in the theme's colors, which people can use without seeing it: a figure named by its title, a summary for screen readers, and a table of every value (visible with showTable). The plot is a tab stop, and the arrow keys move its tooltip from point to point. Each series is labeled in a legend with its own marker shape, so color is never the only cue.
Install
Once per app, with Tailwind CSS v4 and an @/* path alias (Ouro HX is built on Base UI, so --base base; skip -t in an existing app):
npx shadcn@latest init --base base --preset nova --yes --no-monoreponpx shadcn@latest add ourostack/ouro-ui/ouro-base#v1.2.13Then the component. From v0.8.0 it installs only the helpers it imports and never touches your stylesheet (Installing):
npx shadcn@latest add ourostack/ouro-ui/chart#v1.2.13Or, with the @ouro namespace set up:
npx shadcn@latest add @ouro/ouro-base @ouro/chartIts tests, stories and Playwright spec are optional. They need Vitest 4.1.11 or later, and from v0.8.0 never change a version your app has (Testing):
npx shadcn@latest add ourostack/ouro-ui/chart#v1.2.13 ourostack/ouro-ui/chart-tests#v1.2.13import { Chart } from "@/components/ouro/chart/chart";Paths use shadcn's default @/ alias; the CLI rewrites them to yours.
Example
<Chart
title="Recipes cooked per month"
data={months}
categoryKey="month"
config={{ cooked: { label: "Cooked" }, saved: { label: "Saved", tone: "chart-2" } }}
/>Usage
Pass type for bars, lines or areas, one per series in config. For anything else, pass a recharts chart as children with <ChartTooltip /> and <ChartLegend /> inside it, as in shadcn's charts; it draws with var(--color-<key>). The marks Chart draws itself appear at once; your own <Line> or <Bar> keeps recharts' draw-in unless you pass isAnimationActive={false}.
Built on recharts, which Bundlephobia measures at about 150 KB gzip (566 KB minified) for the whole package; a bundler that drops what Chart does not import adds less to the page that renders it. Load it with next/dynamic or React.lazy when the chart is below the fold.
Colors come from the theme's --chart-1 to --chart-5, which must reach 3:1 against the background for the marks to be seen (WCAG's non-text contrast).
Use instead when
- Use
Progressinstead for one value out of a total, and a table alone when readers need exact figures more than the shape of the data.
Props
Type: ChartProps<Row>.
categoryKey(required)- Type:
keyof Row & string - The key in each row that names its category: the x axis and the table's first column.
children- Type:
ReactNode - A recharts chart (
<LineChart>) for anythingtypecannot draw. It getsdata, the title as its name and the theme colors asvar(--color-<key>); add<ChartTooltip />and<ChartLegend />inside it. className- Type:
string - Layout only: the chart's height (
h-64,aspect-square), margins. The plot is 16:9 until you set a height. Appearance classes warn in development. config(required)- Type:
ChartConfig<Row> - The series to draw, by their key in each row, with their labels and tones.
data(required)- Type:
readonly Row[] - The rows to draw, one per category (a month, a recipe).
description- Type:
ReactNode - A line under the title, such as the period: "January to June".
formatValue- Type:
((value: number, series: string) => string) - Default:
"1,250" - Writes a value for the axis, the tooltip and the table, for other languages or units.
seriesis the value's key inconfig, and""for the y axis, which all series share. hideTitle- Type:
boolean - Hides the title visually; screen readers still hear it.
ref- Type:
Ref<HTMLElement> - Reaches the rendered element.
showTable- Type:
boolean - Shows the data table under the chart. It is always there for screen readers.
summary- Type:
((info: ChartSummaryInfo) => string) - Default: (info) => "Bar chart of Cooked and Saved by Month, 3 points. The table that follows lists every value."
- What screen readers hear about the chart after its title, for other languages.
title(required)- Type:
string - What the chart shows: "Recipes cooked per month". Its name for screen readers, shown above it. Required.
type- Type:
"area" | "line" | "bar" - Default:
"bar" - What to draw when there are no children: bars, lines or areas, one per series.
Native attributes
Also accepts the attributes in React's HTMLAttributes (id, aria-*, event handlers), passed to the rendered element, except those named on this page.
className is for layout only
Pass margins, width and grid placement (mt-4, w-full, col-span-2). Your classes always win over Ouro UI's: Chart merges className last with cn (tailwind-merge), so a class that conflicts with its own replaces it.layout-classes
Appearance comes from props, not classes. In development, a class that sets appearance logs one warning per component instance, naming the prop to use instead. A class sets appearance when, after its variants (hover:, sm:) and any ! are removed, it starts with bg-, text-, border-, rounded-, shadow-, font-, ring-, from-, via-, to-, fill- or stroke-, or is border, rounded, shadow or ring, or has a dark: variant. Text wrapping, overflow and table layout classes (text-wrap, text-ellipsis, border-collapse) are layout and do not warn.
Alignment classes (text-center) warn too: set alignment on a parent element.
Types
ChartConfig
The series a chart draws, by their key in each row, as in shadcn's ChartConfig. Each key also names a CSS variable, --color-<key>, for recharts children (fill="var(--color-cooked)"). A label for categoryKey names the category column.
type ChartConfig<Row extends object = Record<string, unknown>> = { [Key in keyof Row & string]?: ChartSeries };ChartSeries
One series in a chart's config: its label and the theme tone it is drawn in.
interface ChartSeries {
/** What the series is called in the legend, the tooltip and the data table: "Recipes cooked". */
label: string;
/**
* The theme color: `chart-1` to `chart-5`, or a tone that means something (`destructive`
* for failures). Without it, series take `chart-1`, `chart-2` and so on, in order.
*/
tone?: ChartTone | (string & { 'Use "chart-1" to "chart-5", "primary", "destructive", "success" or "warning"': never }) | undefined;
/** Not a prop. Colors come from the theme: `{ label: "Cooked", tone: "chart-1" }`. */
color?: { 'Colors come from the theme. Use { label: "Cooked", tone: "chart-1" }': never };
/** Not a prop. Light and dark colors come from the theme's chart tokens: `{ label: "Cooked", tone: "chart-1" }`. */
theme?: { 'Colors come from the theme. Use { label: "Cooked", tone: "chart-1" }': never };
}Claim sources
- layout-classes: test:registry/ouro/components/ouro/chart/chart.test.tsx::Chart > forwards a ref and lets app layout classes win
verify:testExists(registry/ouro/components/ouro/chart/chart.test.tsx::Chart > forwards a ref and lets app layout classes win)