Chart
Recharts wrapper with consistent theming, tooltip, and legend. Supports all chart types.
Examples
Example
Build your chart using Recharts components and the chart container.
import type { ChartConfig } from "@codefast/ui/chart";
import { ChartContainer } from "@codefast/ui/chart";
import { Bar, BarChart } from "recharts";
const chartData = [
{ month: "January", desktop: 186, mobile: 80 },
{ month: "February", desktop: 305, mobile: 200 },
{ month: "March", desktop: 237, mobile: 120 },
{ month: "April", desktop: 73, mobile: 190 },
{ month: "May", desktop: 209, mobile: 130 },
{ month: "June", desktop: 214, mobile: 140 },
];
const chartConfig = {
desktop: {
label: "Desktop",
color: "#2563eb",
},
mobile: {
label: "Mobile",
color: "#60a5fa",
},
} satisfies ChartConfig;
export function ChartExample() {
return (
<ChartContainer config={chartConfig} className="min-h-50 w-full">
<BarChart accessibilityLayer data={chartData}>
<Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
<Bar dataKey="mobile" fill="var(--color-mobile)" radius={4} />
</BarChart>
</ChartContainer>
);
}
Add an Axis
Add an x-axis to the chart with the XAxis component.
import type { ChartConfig } from "@codefast/ui/chart";
import { ChartContainer } from "@codefast/ui/chart";
import { Bar, BarChart, CartesianGrid, XAxis } from "recharts";
const chartData = [
{ month: "January", desktop: 186, mobile: 80 },
{ month: "February", desktop: 305, mobile: 200 },
{ month: "March", desktop: 237, mobile: 120 },
{ month: "April", desktop: 73, mobile: 190 },
{ month: "May", desktop: 209, mobile: 130 },
{ month: "June", desktop: 214, mobile: 140 },
];
const chartConfig = {
desktop: {
label: "Desktop",
color: "#2563eb",
},
mobile: {
label: "Mobile",
color: "#60a5fa",
},
} satisfies ChartConfig;
export function ChartBarDemoAxis() {
return (
<ChartContainer config={chartConfig} className="min-h-50 w-full">
<BarChart accessibilityLayer data={chartData}>
<CartesianGrid vertical={false} />
<XAxis
dataKey="month"
tickLine={false}
tickMargin={10}
axisLine={false}
tickFormatter={(value) => value.slice(0, 3)}
/>
<Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
<Bar dataKey="mobile" fill="var(--color-mobile)" radius={4} />
</BarChart>
</ChartContainer>
);
}
Add a Grid
Add a background grid with the CartesianGrid component.
import type { ChartConfig } from "@codefast/ui/chart";
import { ChartContainer } from "@codefast/ui/chart";
import { Bar, BarChart, CartesianGrid } from "recharts";
const chartData = [
{ month: "January", desktop: 186, mobile: 80 },
{ month: "February", desktop: 305, mobile: 200 },
{ month: "March", desktop: 237, mobile: 120 },
{ month: "April", desktop: 73, mobile: 190 },
{ month: "May", desktop: 209, mobile: 130 },
{ month: "June", desktop: 214, mobile: 140 },
];
const chartConfig = {
desktop: {
label: "Desktop",
color: "#2563eb",
},
mobile: {
label: "Mobile",
color: "#60a5fa",
},
} satisfies ChartConfig;
export function ChartBarDemoGrid() {
return (
<ChartContainer config={chartConfig} className="min-h-50 w-full">
<BarChart accessibilityLayer data={chartData}>
<CartesianGrid vertical={false} />
<Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
<Bar dataKey="mobile" fill="var(--color-mobile)" radius={4} />
</BarChart>
</ChartContainer>
);
}
Add Legend
Add a legend with the ChartLegend and ChartLegendContent components.
import type { ChartConfig } from "@codefast/ui/chart";
import { ChartContainer, ChartLegend, ChartLegendContent, ChartTooltip, ChartTooltipContent } from "@codefast/ui/chart";
import { Bar, BarChart, CartesianGrid, XAxis } from "recharts";
const chartData = [
{ month: "January", desktop: 186, mobile: 80 },
{ month: "February", desktop: 305, mobile: 200 },
{ month: "March", desktop: 237, mobile: 120 },
{ month: "April", desktop: 73, mobile: 190 },
{ month: "May", desktop: 209, mobile: 130 },
{ month: "June", desktop: 214, mobile: 140 },
];
const chartConfig = {
desktop: {
label: "Desktop",
color: "#2563eb",
},
mobile: {
label: "Mobile",
color: "#60a5fa",
},
} satisfies ChartConfig;
export function ChartBarDemoLegend() {
return (
<ChartContainer config={chartConfig} className="min-h-50 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 content={<ChartTooltipContent />} />
<ChartLegend content={<ChartLegendContent />} />
<Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
<Bar dataKey="mobile" fill="var(--color-mobile)" radius={4} />
</BarChart>
</ChartContainer>
);
}
Add Tooltip
Add a themed tooltip with the ChartTooltip and ChartTooltipContent components.
import type { ChartConfig } from "@codefast/ui/chart";
import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@codefast/ui/chart";
import { Bar, BarChart, CartesianGrid, XAxis } from "recharts";
const chartData = [
{ month: "January", desktop: 186, mobile: 80 },
{ month: "February", desktop: 305, mobile: 200 },
{ month: "March", desktop: 237, mobile: 120 },
{ month: "April", desktop: 73, mobile: 190 },
{ month: "May", desktop: 209, mobile: 130 },
{ month: "June", desktop: 214, mobile: 140 },
];
const chartConfig = {
desktop: {
label: "Desktop",
color: "#2563eb",
},
mobile: {
label: "Mobile",
color: "#60a5fa",
},
} satisfies ChartConfig;
export function ChartBarDemoTooltip() {
return (
<ChartContainer config={chartConfig} className="min-h-50 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 content={<ChartTooltipContent />} />
<Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
<Bar dataKey="mobile" fill="var(--color-mobile)" radius={4} />
</BarChart>
</ChartContainer>
);
}
RTL
Right-to-left layout support for languages such as Arabic and Hebrew.
Translations are AI-generated for demonstration and may be imperfect.
import type { ChartConfig } from "@codefast/ui/chart";
import { ChartContainer, ChartLegend, ChartLegendContent, ChartTooltip, ChartTooltipContent } from "@codefast/ui/chart";
import { Bar, BarChart, CartesianGrid, XAxis } from "recharts";
import type { Translations } from "#/features/components-catalog/components/detail/language";
import { useTranslation } from "#/features/components-catalog/components/detail/language-context";
const translations: Translations = {
en: {
dir: "ltr",
values: {
january: "January",
february: "February",
march: "March",
april: "April",
may: "May",
june: "June",
desktop: "Desktop",
mobile: "Mobile",
},
},
ar: {
dir: "rtl",
values: {
january: "يناير",
february: "فبراير",
march: "مارس",
april: "أبريل",
may: "مايو",
june: "يونيو",
desktop: "سطح المكتب",
mobile: "الجوال",
},
},
he: {
dir: "rtl",
values: {
january: "ינואר",
february: "פברואר",
march: "מרץ",
april: "אפריל",
may: "מאי",
june: "יוני",
desktop: "מחשב",
mobile: "נייד",
},
},
};
const chartData = [
{ month: "january", desktop: 186, mobile: 80 },
{ month: "february", desktop: 305, mobile: 200 },
{ month: "march", desktop: 237, mobile: 120 },
{ month: "april", desktop: 73, mobile: 190 },
{ month: "may", desktop: 209, mobile: 130 },
{ month: "june", desktop: 214, mobile: 140 },
];
export function ChartRtl() {
const { t, dir } = useTranslation(translations, "ar");
const chartConfig = {
desktop: {
label: t.desktop,
color: "var(--chart-2)",
},
mobile: {
label: t.mobile,
color: "var(--chart-1)",
},
} satisfies ChartConfig;
return (
<ChartContainer config={chartConfig} className="min-h-50 w-full">
<BarChart accessibilityLayer data={chartData}>
<CartesianGrid vertical={false} orientation={dir === "rtl" ? "right" : "left"} />
<XAxis
dataKey="month"
tickLine={false}
tickMargin={10}
axisLine={false}
tickFormatter={(value) => (t[value as keyof typeof t] as string).slice(0, 3)}
reversed={dir === "rtl"}
/>
<ChartTooltip
content={<ChartTooltipContent labelFormatter={(value) => t[value as keyof typeof t] as string} />}
labelClassName="w-32"
/>
<ChartLegend content={<ChartLegendContent />} />
<Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
<Bar dataKey="mobile" fill="var(--color-mobile)" radius={4} />
</BarChart>
</ChartContainer>
);
}
Tooltip
A chart tooltip contains a label, name, indicator and value. Combine them to customize your tooltip.
import { cn } from "@codefast/ui/lib/utils";
import * as React from "react";
export function ChartTooltipDemo() {
return (
<div className="grid aspect-video w-full max-w-md justify-center text-foreground md:grid-cols-2 [&>div]:relative [&>div]:flex [&>div]:h-34.25 [&>div]:w-56 [&>div]:items-center [&>div]:justify-center [&>div]:p-4">
<div>
<div className="absolute -inset-s-8.75 top-11.25 z-10 text-sm font-medium">Label</div>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 193 40"
width="50"
height="12"
fill="none"
className="absolute inset-s-1.25 top-12.5 z-10"
>
<g clipPath="url(#a)">
<path
fill="currentColor"
d="M173.928 21.13C115.811 44.938 58.751 45.773 0 26.141c4.227-4.386 7.82-2.715 10.567-1.88 21.133 5.64 42.9 6.266 64.457 7.101 31.066 1.253 60.441-5.848 89.183-17.335 1.268-.418 2.325-1.253 4.861-2.924-14.582-2.924-29.165 2.089-41.845-3.76.212-.835.212-1.879.423-2.714 9.51-.627 19.231-1.253 28.742-2.089 9.51-.835 18.808-1.88 28.318-2.506 6.974-.418 9.933 2.924 7.397 9.19-3.17 8.145-7.608 15.664-11.623 23.391-.423.836-1.057 1.88-1.902 2.298-2.325.835-4.65 1.044-7.186 1.67-.422-2.088-1.479-4.386-1.268-6.265.423-2.506 1.902-4.595 3.804-9.19Z"
/>
</g>
<defs>
<clipPath id="a">
<path fill="currentColor" d="M0 0h193v40H0z" />
</clipPath>
</defs>
</svg>
<TooltipDemo
label="Page Views"
payload={[
{ name: "Desktop", value: 186, fill: "var(--chart-1)" },
{ name: "Mobile", value: 80, fill: "var(--chart-2)" },
]}
className="w-32"
/>
</div>
<div className="items-end">
<div className="absolute inset-s-30.5 top-0 z-10 text-sm font-medium">Name</div>
<svg
xmlns="http://www.w3.org/2000/svg"
width="35"
height="42"
fill="none"
viewBox="0 0 122 148"
className="absolute inset-s-21.25 top-2.5 z-10 -scale-x-100"
>
<g clipPath="url(#ab)">
<path
fill="currentColor"
d="M0 2.65c6.15-4.024 12.299-2.753 17.812-.847a115.56 115.56 0 0 1 21.84 10.59C70.4 32.727 88.849 61.744 96.483 97.54c1.908 9.108 2.544 18.639 3.817 29.017 8.481-4.871 12.934-14.402 21.416-19.909 1.061 4.236-1.06 6.989-2.756 9.319-6.998 9.531-14.207 19.062-21.63 28.382-3.604 4.448-6.36 4.871-10.177 1.059-8.058-7.837-12.935-17.368-14.42-28.382 0-.424.636-1.059 1.485-2.118 9.118 2.33 6.997 13.979 14.843 18.215 3.393-14.614.848-28.593-2.969-42.149-4.029-14.19-9.33-27.746-17.812-39.82-8.27-11.86-18.66-21.392-30.11-30.287C26.93 11.758 14.207 6.039 0 2.65Z"
/>
</g>
<defs>
<clipPath id="ab">
<path fill="currentColor" d="M0 0h122v148H0z" />
</clipPath>
</defs>
</svg>
<TooltipDemo
label="Browser"
hideLabel
payload={[
{ name: "Chrome", value: 1286, fill: "var(--chart-3)" },
{ name: "Firefox", value: 1000, fill: "var(--chart-4)" },
]}
indicator="dashed"
className="w-32"
/>
</div>
<div className="hidden! md:flex!">
<TooltipDemo
label="Page Views"
payload={[{ name: "Desktop", value: 12486, fill: "var(--chart-3)" }]}
className="w-36"
indicator="line"
/>
</div>
<div className="items-start! justify-start!">
<div className="absolute inset-s-12.5 top-15 z-10 text-sm font-medium">Indicator</div>
<TooltipDemo
label="Browser"
hideLabel
payload={[{ name: "Chrome", value: 1286, fill: "var(--chart-1)" }]}
indicator="dot"
className="w-32"
/>
<svg
xmlns="http://www.w3.org/2000/svg"
width="15"
height="34"
fill="none"
viewBox="0 0 75 175"
className="absolute inset-s-7.5 top-9.5 z-10 rotate-[-40deg]"
>
<g clipPath="url(#abc)">
<path
fill="currentColor"
d="M20.187 175c-4.439-2.109-7.186-2.531-8.032-4.008-3.17-5.484-6.763-10.968-8.454-17.084-5.073-16.242-4.439-32.694-1.057-49.146 5.707-28.053 18.388-52.942 34.24-76.565 1.692-2.531 3.171-5.063 4.862-7.805 0-.21-.211-.632-.634-1.265-4.65 1.265-9.511 2.53-14.161 3.585-2.537.422-5.496.422-8.032-.421-1.48-.422-3.593-2.742-3.593-4.219 0-1.898 1.48-4.218 2.747-5.906 1.057-1.054 2.96-1.265 4.65-1.687C35.406 7.315 48.088 3.729 60.98.776c10.99-2.53 14.584 1.055 13.95 11.812-.634 11.18-.846 22.358-1.268 33.326-.212 3.375-.846 6.96-1.268 10.757-8.878-4.007-8.878-4.007-12.048-38.177C47.03 33.259 38.153 49.289 29.91 65.741 21.667 82.193 16.17 99.49 13.212 117.84c-2.959 18.984.634 36.912 6.975 57.161Z"
/>
</g>
<defs>
<clipPath id="abc">
<path fill="currentColor" d="M0 0h75v175H0z" />
</clipPath>
</defs>
</svg>
</div>
</div>
);
}
function TooltipDemo({
indicator = "dot",
label,
payload,
hideLabel,
hideIndicator,
className,
}: {
label: string;
hideLabel?: boolean;
hideIndicator?: boolean;
indicator?: "line" | "dot" | "dashed";
payload: Array<{
name: string;
value: number;
fill: string;
}>;
nameKey?: string;
labelKey?: string;
} & React.ComponentProps<"div">) {
const tooltipLabel = hideLabel ? null : <div className="font-medium">{label}</div>;
if (!payload?.length) {
return null;
}
const nestLabel = payload.length === 1 && indicator !== "dot";
return (
<div
className={cn(
"grid min-w-32 items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl transition-all ease-in-out hover:-translate-y-0.5",
className,
)}
>
{!nestLabel ? tooltipLabel : null}
<div className="grid gap-1.5">
{payload.map((item, index) => {
const indicatorColor = item.fill;
return (
<div
key={index}
className={cn(
"flex w-full items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
indicator === "dot" && "items-center",
)}
>
<>
{!hideIndicator && (
<div
className={cn("shrink-0 rounded-xs border-(--color-border) bg-(--color-bg)", {
"h-2.5 w-2.5": indicator === "dot",
"w-1": indicator === "line",
"w-0 border-[1.5px] border-dashed bg-transparent": indicator === "dashed",
"my-0.5": nestLabel && indicator === "dashed",
})}
style={
{
"--color-bg": indicatorColor,
"--color-border": indicatorColor,
} as React.CSSProperties
}
/>
)}
<div
className={cn("flex flex-1 justify-between leading-none", nestLabel ? "items-end" : "items-center")}
>
<div className="grid gap-1.5">
{nestLabel ? tooltipLabel : null}
<span className="text-muted-foreground">{item.name}</span>
</div>
<span className="font-mono font-medium text-foreground tabular-nums">
{item.value.toLocaleString()}
</span>
</div>
</>
</div>
);
})}
</div>
</div>
);
}
Anatomy
How the parts nest — every slot the component exposes, in composition order.
Features
- ChartConfig maps each data series to a label and either a flat color or a light/dark theme pair, exposed as --color-<key> CSS variables Recharts components reference directly.
- ChartTooltipContent/ChartLegendContent are drop-in replacements for Recharts' own tooltip and legend that read colors and labels from that same config.
- Works with any Recharts chart type (Bar/Line/Area/Pie…) — ChartContainer only supplies the responsive wrapper and theme variables.
API reference
Props for each part of the component. All native element props are also forwarded.
ChartContainer
Wraps a Recharts chart and supplies CSS variables from config.
configChartConfigMaps each series key to a label and colour (exposed as --color-<key>).
childrenReactNodeAny Recharts chart (BarChart, LineChart, AreaChart…).
ChartTooltip
Recharts' own Tooltip, re-exported as-is.
contentReactNodePass <ChartTooltipContent /> for themed, config-aware tooltips.
ChartTooltipContent
Themed tooltip content that reads colours and labels from config.
hideLabelbooleanHides the tooltip's label row.
Default
falsehideIndicatorbooleanHides the colour indicator next to each series.
Default
falseindicator"dot" | "line" | "dashed"The shape of the colour indicator.
Default
"dot"
Accessibility
Built to be keyboard-navigable and screen-reader friendly out of the box.
- Set accessibilityLayer on the Recharts chart for keyboard and screen-reader support.
- Pair charts with a caption or table — don’t rely on visuals alone for key numbers.
- Use distinct colours and labels, not colour alone, to tell series apart.
Guidelines
Conventions that keep usage consistent across an app.
Do
- Define every series in config so colours and labels stay consistent.
- Keep axes and tooltips uncluttered.
Don’t
- Don’t encode meaning with colour only.
- Don’t use a chart where a single number or table is clearer.
Explore further
Ready to integrate?
Follow the Getting Started guide to install @codefast/ui, or browse the full component gallery.