Nivo provides a rich set of chart types built on D3 — <ResponsiveBar data={data} keys={["value"]} indexBy="category"> renders bar charts. <ResponsiveLine data={series}> renders line charts. <ResponsiveHeatMap data={matrix} axisTop={...}> renders heatmaps. <ResponsiveTreeMap data={hierarchy} identity="name" value="size"> renders treemaps. <ResponsiveSunburst data={root}> renders multi-level donut charts. <ResponsiveCalendar data={days} from="2024-01-01" to="2024-12-31"> renders GitHub-style activity calendars. <ResponsiveChord data={matrix} keys={labels}> renders chord diagrams. <ResponsiveNetwork data={{ nodes, links }}> renders force-directed networks. Theming: const theme = { background: "#fff", text: { fontSize: 11 }, grid: { line: { stroke: "#f0f0f0" } } }. Motion: motionConfig="gentle". Custom tooltip: tooltip={({ id, value, color }) => <div>{id}: {value}</div>}. All Responsive* variants auto-fill their container. Claude Code generates Nivo heatmaps, sunburst charts, calendar views, and treemaps.
CLAUDE.md for Nivo
## Nivo Stack
- Version: @nivo/core >= 0.87, @nivo/bar, @nivo/line, @nivo/heatmap, @nivo/treemap (install each used)
- Responsive: wrap in <div className="h-[300px]"> and use Responsive* variants
- Theme: const nivoTheme: Theme = { background: "transparent", text: { fontSize: 11, fill: "hsl(var(--muted-foreground))" }, grid: { line: { stroke: "hsl(var(--border))" } }, axis: { ticks: { line: { stroke: "hsl(var(--border))" } } } }
- Tooltip: tooltip={({ datum }) => <div className="bg-popover border rounded-lg px-3 py-2 text-xs shadow-lg">{datum.label}: {datum.value}</div>}
- Motion: motionConfig="gentle" or motionConfig={{ mass: 1, tension: 170, friction: 26 }}
Nivo Bar and Line Charts
// components/charts/NivoDashboard.tsx — Nivo bar and line charts
"use client"
import { ResponsiveBar } from "@nivo/bar"
import { ResponsiveLine } from "@nivo/line"
import type { Theme, BarDatum, LineSvgProps } from "@nivo/core"
const NIVO_THEME: Theme = {
background: "transparent",
text: { fontSize: 11, fill: "#6b7280" },
grid: { line: { stroke: "#f3f4f6", strokeWidth: 1 } },
axis: {
domain: { line: { stroke: "transparent" } },
ticks: { line: { stroke: "#e5e7eb" }, text: { fill: "#6b7280", fontSize: 11 } },
},
crosshair: { line: { stroke: "#6366f1", strokeOpacity: 0.3, strokeWidth: 1 } },
tooltip: {
container: {
background: "#fff",
border: "1px solid #e5e7eb",
borderRadius: "12px",
boxShadow: "0 4px 24px rgba(0,0,0,.08)",
padding: "8px 12px",
fontSize: 12,
},
},
}
// ── Bar chart ────────────────────────────────────────────────────────────────
type BarData = { category: string; [metric: string]: number | string }
interface NivoBarChartProps {
data: BarData[]
keys: string[]
colors?: string[]
height?: number
groupMode?: "grouped" | "stacked"
}
export function NivoBarChart({
data,
keys,
colors = ["#6366f1", "#3b82f6", "#22c55e", "#f59e0b"],
height = 300,
groupMode = "grouped",
}: NivoBarChartProps) {
return (
<div style={{ height }} className="rounded-2xl border bg-card p-4">
<ResponsiveBar
data={data as BarDatum[]}
keys={keys}
indexBy="category"
groupMode={groupMode}
margin={{ top: 16, right: 16, bottom: 48, left: 56 }}
padding={0.25}
innerPadding={groupMode === "grouped" ? 4 : 0}
colors={colors}
borderRadius={4}
axisLeft={{
tickSize: 0,
tickPadding: 8,
format: (v) => `${Number(v).toLocaleString()}`,
}}
axisBottom={{
tickSize: 0,
tickPadding: 8,
}}
enableLabel={false}
enableGridX={false}
theme={NIVO_THEME}
motionConfig="gentle"
animate
/>
</div>
)
}
// ── Line chart ───────────────────────────────────────────────────────────────
type LineSeries = { id: string; color: string; data: { x: string; y: number }[] }
interface NivoLineChartProps {
series: LineSeries[]
height?: number
enableArea?: boolean
}
export function NivoLineChart({ series, height = 300, enableArea = false }: NivoLineChartProps) {
return (
<div style={{ height }} className="rounded-2xl border bg-card p-4">
<ResponsiveLine
data={series}
margin={{ top: 16, right: 24, bottom: 48, left: 56 }}
xScale={{ type: "point" }}
yScale={{ type: "linear", min: "auto", max: "auto", stacked: false }}
curve="monotoneX"
colors={series.map((s) => s.color)}
lineWidth={2}
pointSize={6}
pointBorderWidth={2}
pointBorderColor={{ from: "serieColor" }}
pointColor="white"
enableArea={enableArea}
areaOpacity={0.1}
enableGridX={false}
axisLeft={{
tickSize: 0,
tickPadding: 8,
format: (v) => `${Number(v).toLocaleString()}`,
}}
axisBottom={{ tickSize: 0, tickPadding: 8 }}
useMesh
theme={NIVO_THEME}
motionConfig="gentle"
legends={[{
anchor: "bottom",
direction: "row",
justify: false,
translateX: 0,
translateY: 48,
itemWidth: 100,
itemHeight: 20,
symbolShape: "circle",
symbolSize: 8,
itemTextColor: "#6b7280",
}]}
/>
</div>
)
}
Heatmap and Calendar
// components/charts/NivoHeatmapCalendar.tsx — activity heatmap and calendar
"use client"
import { ResponsiveHeatMap } from "@nivo/heatmap"
import { ResponsiveCalendar } from "@nivo/calendar"
// ── Heatmap (matrix) ─────────────────────────────────────────────────────────
type HeatCell = { x: string; y: number }
type HeatRow = { id: string; data: HeatCell[] }
interface ActivityHeatmapProps {
data: HeatRow[]
height?: number
}
export function ActivityHeatmap({ data, height = 280 }: ActivityHeatmapProps) {
return (
<div style={{ height }} className="rounded-2xl border bg-card p-4">
<ResponsiveHeatMap
data={data}
margin={{ top: 40, right: 24, bottom: 24, left: 80 }}
axisTop={{
tickSize: 0,
tickPadding: 8,
tickRotation: -30,
legend: "",
}}
axisLeft={{
tickSize: 0,
tickPadding: 8,
}}
colors={{ type: "sequential", scheme: "purples" }}
cellComponent="rect"
emptyColor="#f9fafb"
borderRadius={4}
borderWidth={2}
borderColor="#fff"
enableLabels={false}
animate
motionConfig="gentle"
tooltip={({ cell }) => (
<div className="bg-white border rounded-lg px-3 py-2 text-xs shadow">
<strong>{cell.serieId}</strong> / {cell.data.x}: <strong>{cell.value ?? "—"}</strong>
</div>
)}
/>
</div>
)
}
// ── Calendar (GitHub-style) ──────────────────────────────────────────────────
type CalDay = { day: string; value: number }
interface ActivityCalendarProps {
data: CalDay[]
from: string // "2024-01-01"
to: string // "2024-12-31"
height?: number
}
export function ActivityCalendar({ data, from, to, height = 180 }: ActivityCalendarProps) {
return (
<div style={{ height }} className="rounded-2xl border bg-card p-4">
<ResponsiveCalendar
data={data}
from={from}
to={to}
emptyColor="#f3f4f6"
colors={["#c7d2fe", "#818cf8", "#6366f1", "#4338ca", "#312e81"]}
margin={{ top: 24, right: 16, bottom: 8, left: 36 }}
yearSpacing={40}
monthBorderColor="#fff"
dayBorderWidth={2}
dayBorderColor="#fff"
daySpacing={3}
legends={[{
anchor: "bottom-right",
direction: "row",
justify: false,
itemCount: 5,
itemWidth: 34,
itemHeight: 36,
itemsSpacing: 4,
symbolSize: 20,
}]}
tooltip={({ day, value, color }) => (
<div className="bg-white border rounded-lg px-3 py-2 text-xs shadow">
<span style={{ color }}>{day}</span>: <strong>{value} contributions</strong>
</div>
)}
/>
</div>
)
}
Treemap
// components/charts/NivoTreemap.tsx — hierarchical treemap
"use client"
import { ResponsiveTreeMap } from "@nivo/treemap"
type TreeNode = { name: string; value?: number; color?: string; children?: TreeNode[] }
interface NivoTreemapProps {
data: TreeNode
height?: number
}
export function NivoTreemap({ data, height = 340 }: NivoTreemapProps) {
return (
<div style={{ height }} className="rounded-2xl border bg-card overflow-hidden">
<ResponsiveTreeMap
data={data}
identity="name"
value="value"
valueFormat=".02s"
innerPadding={4}
outerPadding={8}
colors={{ scheme: "purples" }}
borderWidth={2}
borderColor={{ from: "color", modifiers: [["darker", 0.3]] }}
labelSkipSize={16}
label={({ node }) => node.data.name}
labelTextColor={{ from: "color", modifiers: [["darker", 3]] }}
parentLabelSize={24}
parentLabelTextColor={{ from: "color", modifiers: [["darker", 2]] }}
animate
motionConfig="gentle"
tooltip={({ node }) => (
<div className="bg-white border rounded-lg px-3 py-2 text-xs shadow">
<strong>{node.data.name}</strong>: {node.formattedValue}
</div>
)}
/>
</div>
)
}
For the Recharts alternative when a simpler React JSX component API, smaller bundle (no need for all chart types), and more community tutorials are preferred — Recharts covers Bar, Line, Area, Pie, and Scatter charts with less setup while Nivo excels for specialized chart types like heatmaps, treemaps, sunbursts, chord diagrams, and calendars that Recharts doesn’t offer, see the Recharts guide. For the D3.js alternative when the exact visual output and rendering performance must be controlled at every pixel — Nivo wraps D3 internally; drop down to raw D3 only when Nivo’s layout algorithms aren’t customizable enough for a specific visualization, see the D3.js guide. The Claude Skills 360 bundle includes Nivo skill sets covering heatmaps, treemaps, calendars, and chord diagrams. Start with the free tier to try specialized chart generation.