Charts
Vui Starter charts on Recharts, wrapped in a small themed ChartContainer that maps your data keys to the --chart-* tokens. Charts stay in sync with the theme and flip with dark mode, with no per-chart styling to maintain.
Why Recharts
Recharts is the same charting layer shadcn/ui builds on: composable React components, SSR-friendly, and driven by CSS variables. Since Vui already defines --chart-1 through --chart-5 for both light and dark in theme.css, your charts pick up the palette without any extra configuration.
Install
Recharts ships with Vui UI. In a standalone app, install it once:
npm install rechartsMonorepo
@viliha/vui-ui and the backoffice app, so no install is needed.The wrapper
Import the themed pieces from @viliha/vui-ui/chart, and pull the chart primitives (AreaChart, Bar, XAxis, …) straight from recharts.
Area chart
Define a config keyed by your data keys, then reference the variables it generates, such as fill="var(--color-revenue)".
"use client";
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from "recharts";
import {
ChartContainer,
ChartTooltip,
ChartTooltipContent,
type ChartConfig,
} from "@viliha/vui-ui/chart";
const data = [
{ month: "Jan", revenue: 18600 },
{ month: "Feb", revenue: 30500 },
{ month: "Mar", revenue: 23700 },
];
const config: ChartConfig = {
revenue: { label: "Revenue", color: "var(--chart-1)" },
};
export function RevenueChart() {
return (
<ChartContainer config={config}>
<AreaChart data={data}>
<CartesianGrid vertical={false} />
<XAxis dataKey="month" tickLine={false} axisLine={false} />
<YAxis width={40} tickLine={false} axisLine={false} />
<ChartTooltip content={<ChartTooltipContent />} />
<Area
dataKey="revenue"
type="natural"
stroke="var(--color-revenue)"
fill="var(--color-revenue)"
fillOpacity={0.15}
strokeWidth={2}
/>
</AreaChart>
</ChartContainer>
);
}Bar, line, and pie
The same wrapper handles every Recharts chart. Swap AreaChart/Area for BarChart/Bar, LineChart/Line, or PieChart/Pie. For a pie, color each slice with a Cell and key the config by slice name, so the tooltip and legend pick up the labels.
import { Cell, Pie, PieChart } from "recharts";
import {
ChartContainer,
ChartLegend,
ChartLegendContent,
ChartTooltip,
ChartTooltipContent,
} from "@viliha/vui-ui/chart";
const data = [
{ name: "Direct", value: 4200, color: "var(--chart-1)" },
{ name: "Organic", value: 5400, color: "var(--chart-3)" },
];
<ChartContainer config={{ Direct: { label: "Direct", color: "var(--chart-1)" } }}>
<PieChart>
<ChartTooltip content={<ChartTooltipContent />} />
<ChartLegend content={<ChartLegendContent />} />
<Pie data={data} dataKey="value" nameKey="name" innerRadius={55}>
{data.map((d) => (
<Cell key={d.name} fill={d.color} />
))}
</Pie>
</PieChart>
</ChartContainer>See it live
/charts.Which should I use, Recharts or TanStack Charts?
Use Recharts if your app is React and stays React. It is what ChartContainer wraps, it is what the demo uses, and nothing about it is changing.
Use TanStack Charts if the same chart has to exist in more than one framework, or you want a grammar-of-graphics API rather than a component per chart type. One definition renders in React, Vue, Svelte, Solid, Angular, Lit and Alpine, which is why it is how Vue gets charts at all: Recharts is React-only.
Both read the same tokens, so they look like the same product. Recharts reads --chart-1 to --chart-5 directly. TanStack paints with currentColor and reads its own --ts-chart-* palette, and the .vui-chart class in theme.css maps ours onto those, so light mode, dark mode and a per-tenant brand all just work.
TanStack Charts in React
"use client";
import { defineChart, lineY } from "@tanstack/charts";
import { scaleLinear } from "@tanstack/charts/scales/linear";
import { scalePoint } from "@tanstack/charts/scales/point";
import { TanStackChart } from "@viliha/vui-ui/tanstack-chart";
const revenue = [
{ month: "Jan", revenue: 42_000 },
{ month: "Feb", revenue: 58_000 },
{ month: "Mar", revenue: 76_000 },
];
const chart = defineChart({
marks: [lineY(revenue, { id: "revenue", x: "month", y: "revenue", points: true })],
x: { scale: () => scalePoint<string>().padding(0.2) },
y: { scale: scaleLinear, nice: true, grid: true },
});
export function RevenueChart() {
return <TanStackChart definition={chart} ariaLabel="Monthly revenue" height={280} />;
}The same chart in Vue
<script setup lang="ts">
import { Chart } from "@viliha/vui-vue";
// `chart` is the exact definition from the React example: it is framework-neutral.
import { chart } from "./revenue-definition";
</script>
<template>
<Chart :definition="chart" aria-label="Monthly revenue" :height="280" />
</template>@tanstack/charts is an optional peer dependency of both packages, so it only costs you anything if you use it:
npm install @tanstack/chartsVersion