Charts
Monark charts are Recharts 3 wrapped by shadcn's chart component. You write ordinary Recharts (BarChart, Line, Pie, ...) inside a ChartContainer. The wrapper adds the theme colors, a responsive container, and a tooltip and legend that match the rest of the registry.
npx shadcn add @monark/chart
This installs components/ui/chart.tsx and adds recharts to your dependencies. The chart preview on this site shows every type below, with tooltip and legend options.
There is no diagram engine in the registry. Charts plot data. For flowcharts, sequence diagrams or graphs of nodes and edges, use a dedicated library such as Mermaid or React Flow.
Colors come from ChartConfig
Every chart takes a ChartConfig. Each key is a series (or a slice, for pie charts). It gives the series a label for the tooltip and legend, and a color.
import { type ChartConfig } from "@/components/ui/chart"
const config = {
eth: { label: "ETH", color: "var(--chart-1)" },
usdc: { label: "USDC", color: "var(--chart-2)" },
} satisfies ChartConfig
ChartContainer turns each key into a CSS variable scoped to that chart: eth becomes --color-eth. Use the variable on the Recharts elements, never a hex value:
<Bar dataKey="eth" fill="var(--color-eth)" />
The theme ships five chart tokens, --chart-1 to --chart-5. --chart-1 is the primary (Monark orange), darkened in light mode to #cd6600 so it stays readable on cream, and it follows a remapped --primary. The other four are a red, a brown, a khaki tan and a neutral, with lighter values in dark mode. All five meet 3:1 against the background and cards in both modes. Point your config at these tokens and the chart switches with the theme.
If a series needs a color outside the tokens, give it one per mode instead of color:
const config = {
sol: { label: "SOL", theme: { light: "#6d28d9", dark: "#a78bfa" } },
} satisfies ChartConfig
Give the container a height. A chart with no height draws nothing.
<ChartContainer config={config} className="h-72 w-full">
{/* chart */}
</ChartContainer>
Bar charts
Grouped bars sit side by side. Add the same stackId to stack them. Set layout="vertical" on the chart for horizontal bars, with a number XAxis and a category YAxis.
import { Bar, BarChart, CartesianGrid, XAxis } from "recharts"
import {
ChartContainer,
ChartLegend,
ChartLegendContent,
ChartTooltip,
ChartTooltipContent,
} from "@/components/ui/chart"
<ChartContainer config={config} className="h-72 w-full">
<BarChart accessibilityLayer data={volume}>
<CartesianGrid vertical={false} />
<XAxis dataKey="month" tickLine={false} axisLine={false} tickMargin={10} />
<ChartTooltip content={<ChartTooltipContent />} />
<ChartLegend content={<ChartLegendContent />} />
<Bar dataKey="eth" fill="var(--color-eth)" radius={4} />
<Bar dataKey="usdc" fill="var(--color-usdc)" radius={4} />
</BarChart>
</ChartContainer>
Line and area charts
Lines and areas use the same data shape as bars. stackId stacks areas too.
<AreaChart accessibilityLayer data={volume}>
<CartesianGrid vertical={false} />
<XAxis dataKey="month" tickLine={false} axisLine={false} tickMargin={10} />
<ChartTooltip content={<ChartTooltipContent indicator="line" />} />
<Area dataKey="usdc" type="natural" stackId="a" fill="var(--color-usdc)" fillOpacity={0.4} stroke="var(--color-usdc)" />
<Area dataKey="eth" type="natural" stackId="a" fill="var(--color-eth)" fillOpacity={0.4} stroke="var(--color-eth)" />
</AreaChart>
For a gradient fill, define a linearGradient in <defs> from the same variable and point fill at it. Gradient ids are global to the page, so make them unique (for example with useId) if a page shows more than one chart.
<AreaChart accessibilityLayer data={volume}>
<defs>
<linearGradient id="fill-eth" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor="var(--color-eth)" stopOpacity={0.8} />
<stop offset="95%" stopColor="var(--color-eth)" stopOpacity={0.1} />
</linearGradient>
</defs>
<Area dataKey="eth" type="natural" fill="url(#fill-eth)" stroke="var(--color-eth)" />
</AreaChart>
For a line chart, swap AreaChart and Area for LineChart and <Line stroke="var(--color-eth)" dot={false} />.
Pie and donut charts
In a pie chart each slice is a config key. Put the color on each data row with fill, and pass nameKey to the tooltip and legend so they look up the right label.
const allocation = [
{ token: "eth", value: 1820, fill: "var(--color-eth)" },
{ token: "usdc", value: 1240, fill: "var(--color-usdc)" },
{ token: "wbtc", value: 640, fill: "var(--color-wbtc)" },
]
<PieChart accessibilityLayer>
<ChartTooltip content={<ChartTooltipContent nameKey="token" hideLabel />} />
<ChartLegend content={<ChartLegendContent nameKey="token" />} />
<Pie data={allocation} dataKey="value" nameKey="token" innerRadius={60}>
<Label
content={({ viewBox }) =>
viewBox && "cx" in viewBox ? (
<text x={viewBox.cx} y={viewBox.cy} textAnchor="middle" dominantBaseline="middle">
<tspan className="fill-foreground text-2xl font-bold">$3.7M</tspan>
</text>
) : null
}
/>
</Pie>
</PieChart>
innerRadius makes it a donut. Leave it out for a full pie. The Label inside the Pie puts a total in the hole.
Radar and radial charts
A radar chart compares a few series across the same set of measures. A radial bar chart shows one value per row as a ring, which suits percentages like pool utilisation.
<RadarChart accessibilityLayer data={scores}>
<ChartTooltip content={<ChartTooltipContent />} />
<PolarGrid />
<PolarAngleAxis dataKey="metric" />
<Radar dataKey="aave" fill="var(--color-aave)" fillOpacity={0.5} stroke="var(--color-aave)" />
</RadarChart>
<RadialBarChart accessibilityLayer data={utilisation} innerRadius={40} outerRadius={120}>
<PolarAngleAxis type="number" domain={[0, 100]} tick={false} />
<ChartTooltip content={<ChartTooltipContent nameKey="pool" hideLabel />} />
<RadialBar dataKey="utilisation" background cornerRadius={8} />
</RadialBarChart>
The PolarAngleAxis with a fixed domain makes each ring a share of 100 instead of a share of the largest value. Radial rows carry their own fill, like pie slices.
Accessibility
A chart is a picture of data. Some people can't see it, and some can't tell its colors apart. Plan for both.
- Keep
accessibilityLayeron. Recharts 3 turns it on by default; we pass it explicitly so it is obvious. It makes the chart a single tab stop. Once focused, the left and right arrow keys move the tooltip between data points, so keyboard users can read every value. Don't turn it off on a chart that has a tooltip. - Always give a text alternative. Add a one-line summary next to the chart ("ETH volume peaked in February at $305M"). For data people need to compare, add a table with the same numbers, visible or behind a "Show data" toggle. Link the summary with
aria-describedbyon the container if it isn't next to it. - Don't rely on color alone. Show a legend or label the series directly. For pie and donut charts, label the slices or list the values in the legend. When two series sit close together, tell them apart with something besides color: a dashed
strokeDasharrayline, a different dot shape, or a pattern fill. - Check contrast. Graphics need 3:1 against the background. Every chart token passes in both modes (the lowest is
--chart-4at 3.3:1 on cream). If you remap the palette, keep that floor, and don't let colour alone tell two series apart: add labels, a legend or different line styles. - Respect reduced motion. Recharts animates on mount and on data changes. Pass
isAnimationActive={false}on each series whenprefers-reduced-motionis set.