npm

Reference

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:

terminal
npm install recharts

Monorepo

In this repo Recharts is already a dependency of @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.

  • ChartContainer: sets a --color-<key> CSS variable for every entry in your config and wraps a responsive container.
  • ChartTooltip / ChartTooltipContent: a styled tooltip that reads labels and colors from the config.
  • ChartLegend / ChartLegendContent: a styled legend.

Area chart

Define a config keyed by your data keys, then reference the variables it generates, such as fill="var(--color-revenue)".

revenue-chart.tsx
"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.

traffic-donut.tsx
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

The backoffice demo has a full Charts page (area, bar, line, donut) at /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

app/(app)/reports/revenue-chart.tsx
"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

RevenueChart.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:

terminal
npm install @tanstack/charts

Version

TanStack Charts is pre-1.0 (0.9 at the time of writing), so its API can still move between minor versions. Recharts stays the safer default for a React-only app.