Chart
Installation
npm install clsx@^2.1.1 recharts@^3.8.1 tailwind-merge@^3.4.0
lib/utils.ts
components/chart/chart.tsx
components/chart/index.ts
Code
'use client';
import { useId } from 'react';
import { Bar, BarChart, CartesianGrid, XAxis } from 'recharts';
import {
type ChartConfig,
ChartContainer,
ChartLegend,
ChartLegendContent,
ChartTooltip,
ChartTooltipContent,
} from '@/components/chart/chart';
const data = [
{ month: 'January', desktop: 186, mobile: 80 },
{ month: 'February', desktop: 305, mobile: 200 },
{ month: 'March', desktop: 237, mobile: 120 },
{ month: 'April', desktop: 173, mobile: 190 },
{ month: 'May', desktop: 209, mobile: 130 },
{ month: 'June', desktop: 264, mobile: 140 },
];
const config = {
desktop: {
label: 'Desktop',
color: 'var(--nx-color-chart-categorical-1)',
icon: DesktopSwatch,
},
mobile: {
label: 'Mobile',
color: 'var(--nx-color-chart-categorical-2)',
icon: MobileSwatch,
},
} satisfies ChartConfig;
const shortMonth = (value: string) => value.slice(0, 3);
function HatchPattern({ id }: { id: string }) {
return (
<pattern id={id} width={6} height={6} patternUnits="userSpaceOnUse">
<rect width={6} height={6} fill="var(--color-mobile)" />
<path
d="M0 0L6 6M-3 3L3 9M3 -3L9 3"
stroke="var(--nx-color-container)"
strokeWidth={1.5}
/>
</pattern>
);
}
function DesktopSwatch() {
return (
<svg viewBox="0 0 12 12" aria-hidden="true">
<rect width={12} height={12} rx={2} fill="var(--color-desktop)" />
</svg>
);
}
function MobileSwatch() {
const pattern = useId();
return (
<svg viewBox="0 0 12 12" aria-hidden="true">
<defs>
<HatchPattern id={pattern} />
</defs>
<rect width={12} height={12} rx={2} fill={`url(#${pattern})`} />
</svg>
);
}
export default function ChartDemo() {
const mobilePattern = useId();
return (
<ChartContainer config={config} className="nx:w-full nx:max-w-md">
<BarChart data={data}>
<defs>
<HatchPattern id={mobilePattern} />
</defs>
<CartesianGrid vertical={false} />
<XAxis
dataKey="month"
tickLine={false}
axisLine={false}
tickMargin={8}
tickFormatter={shortMonth}
/>
<ChartTooltip content={<ChartTooltipContent />} />
<ChartLegend content={<ChartLegendContent />} />
<Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
<Bar dataKey="mobile" fill={`url(#${mobilePattern})`} radius={4} />
</BarChart>
</ChartContainer>
);
}
Props
ChartContainer
ChartContainer props| Prop | Type | Default | Description |
|---|
configRequired | ChartConfig | —No default documented | —No description |
|---|
ChartLegend
ChartLegend adds no props of its own; it accepts the props of the element or primitive it wraps.
ChartLegendContent
ChartLegendContent props| Prop | Type | Default | Description |
|---|
className | string | —No default documented | —No description |
|---|
hideIcon | boolean | false | —No description |
|---|
nameKey | string | —No default documented | —No description |
|---|
verticalAlign | "bottom" | "top" | "bottom" | —No description |
|---|
ChartTooltip adds no props of its own; it accepts the props of the element or primitive it wraps.
ChartTooltipContent
ChartTooltipContent props| Prop | Type | Default | Description |
|---|
active | boolean | —No default documented | —No description |
|---|
className | string | —No default documented | —No description |
|---|
color | string | —No default documented | —No description |
|---|
formatter | ChartTooltipFormatter | —No default documented | —No description |
|---|
hideIndicator | boolean | false | —No description |
|---|
hideLabel | boolean | false | —No description |
|---|
indicator | "dashed" | "line" | "dot" | "dot" | —No description |
|---|
labelKey | string | —No default documented | —No description |
|---|
nameKey | string | —No default documented | —No description |
|---|
Examples
Area
'use client';
import { Area, AreaChart, CartesianGrid, XAxis } from 'recharts';
import {
type ChartConfig,
ChartContainer,
ChartLegend,
ChartLegendContent,
ChartTooltip,
ChartTooltipContent,
} from '@/components/chart/chart';
const data = [
{ month: 'January', desktop: 186, mobile: 80 },
{ month: 'February', desktop: 305, mobile: 200 },
{ month: 'March', desktop: 237, mobile: 120 },
{ month: 'April', desktop: 173, mobile: 190 },
{ month: 'May', desktop: 209, mobile: 130 },
{ month: 'June', desktop: 264, mobile: 140 },
];
const config = {
desktop: {
label: 'Desktop',
color: 'var(--nx-color-chart-categorical-1)',
icon: DesktopSwatch,
},
mobile: {
label: 'Mobile',
color: 'var(--nx-color-chart-categorical-2)',
icon: MobileSwatch,
},
} satisfies ChartConfig;
const shortMonth = (value: string) => value.slice(0, 3);
function AreaSwatch({ color, dashed }: { color: string; dashed?: boolean }) {
return (
<svg viewBox="0 0 12 12" aria-hidden="true">
<rect
x={1}
y={1}
width={10}
height={10}
rx={2}
fill={color}
fillOpacity={0.4}
stroke={color}
strokeWidth={1.5}
strokeDasharray={dashed ? '3 2' : undefined}
/>
</svg>
);
}
function DesktopSwatch() {
return <AreaSwatch color="var(--color-desktop)" />;
}
function MobileSwatch() {
return <AreaSwatch color="var(--color-mobile)" dashed />;
}
export default function ChartArea() {
return (
<ChartContainer config={config} className="nx:w-full nx:max-w-md">
<AreaChart data={data} margin={{ left: 12, right: 12 }}>
<CartesianGrid vertical={false} />
<XAxis
dataKey="month"
tickLine={false}
axisLine={false}
tickMargin={8}
tickFormatter={shortMonth}
/>
<ChartTooltip content={<ChartTooltipContent />} />
<ChartLegend content={<ChartLegendContent />} />
<Area
dataKey="desktop"
type="natural"
fill="var(--color-desktop)"
fillOpacity={0.4}
stroke="var(--color-desktop)"
/>
<Area
dataKey="mobile"
type="natural"
fill="var(--color-mobile)"
fillOpacity={0.4}
stroke="var(--color-mobile)"
strokeDasharray="6 4"
/>
</AreaChart>
</ChartContainer>
);
}
Line
'use client';
import { CartesianGrid, Line, LineChart, XAxis } from 'recharts';
import {
type ChartConfig,
ChartContainer,
ChartLegend,
ChartLegendContent,
ChartTooltip,
ChartTooltipContent,
} from '@/components/chart/chart';
const data = [
{ month: 'January', desktop: 186, mobile: 80 },
{ month: 'February', desktop: 305, mobile: 200 },
{ month: 'March', desktop: 237, mobile: 120 },
{ month: 'April', desktop: 173, mobile: 190 },
{ month: 'May', desktop: 209, mobile: 130 },
{ month: 'June', desktop: 264, mobile: 140 },
];
const config = {
desktop: {
label: 'Desktop',
color: 'var(--nx-color-chart-categorical-1)',
icon: DesktopSwatch,
},
mobile: {
label: 'Mobile',
color: 'var(--nx-color-chart-categorical-2)',
icon: MobileSwatch,
},
} satisfies ChartConfig;
const shortMonth = (value: string) => value.slice(0, 3);
function LineSwatch({ color, dashed }: { color: string; dashed?: boolean }) {
return (
<svg viewBox="0 0 12 12" aria-hidden="true">
<line
x1={0}
y1={6}
x2={12}
y2={6}
stroke={color}
strokeWidth={2}
strokeDasharray={dashed ? '3 2' : undefined}
/>
</svg>
);
}
function DesktopSwatch() {
return <LineSwatch color="var(--color-desktop)" />;
}
function MobileSwatch() {
return <LineSwatch color="var(--color-mobile)" dashed />;
}
export default function ChartLine() {
return (
<ChartContainer config={config} className="nx:w-full nx:max-w-md">
<LineChart data={data} margin={{ left: 12, right: 12 }}>
<CartesianGrid vertical={false} />
<XAxis
dataKey="month"
tickLine={false}
axisLine={false}
tickMargin={8}
tickFormatter={shortMonth}
/>
<ChartTooltip content={<ChartTooltipContent />} />
<ChartLegend content={<ChartLegendContent />} />
<Line
dataKey="desktop"
type="natural"
stroke="var(--color-desktop)"
strokeWidth={2}
dot={false}
/>
<Line
dataKey="mobile"
type="natural"
stroke="var(--color-mobile)"
strokeDasharray="6 4"
strokeWidth={2}
dot={false}
/>
</LineChart>
</ChartContainer>
);
}