Skip to content
Charts

Nivo — Component Library Guide

Declarative D3-powered chart components for React with server-side rendering, motion, and a docs site that generates the code for you.

TypeScript MIT
1.7M weekly downloads
14.1k GitHub stars
62.6 kB min+gzip bundle size
v0.99.0 latest version

Figures above measured on from the npm registry (latest version, last-week downloads) and the GitHub API (stars). Not copied from the project's own README, and re-measured rather than edited by hand, so the date tells you exactly how old these numbers are.

How the bundle size was measured. We installed @nivo/core@0.99.0 on its own, bundled export * from '@nivo/core' with esbuild (esm, browser, minified, production), marked React external because your app already has it, and gzipped the result. Measured . This is the ceiling, not the typical cost: it imports the entire public surface with no tree-shaking credit. Pull one component from a well-shaken library and you'll pay a fraction of it. We publish the ceiling because it's the number we can reproduce, and reproducing it is the point.

chartsd3datavizsvgcanvasssr

TL;DR: Nivo wraps D3 in declarative React components. You pass data and props, it draws the chart. Every family is a separate package, SVG variants render server-side, and the docs site builds the code for you as you click through options. Docs: nivo.rocks.

What is Nivo?

Nivo is a chart library built on top of D3's math, with React doing the rendering. That split matters. D3 gives it scales, shapes and layouts that have been correct for a decade; React means you describe a chart as <ResponsiveBar data={data} keys={keys} /> rather than imperatively selecting and appending nodes.

The catalogue is wide: bar, line, pie, scatter, heatmap, treemap, sunburst, sankey, calendar, chord, network, geo, radar, bullet, funnel. Most families ship in two flavours, SVG and Canvas, sometimes with an HTML variant too.

When to use it

Reach for Nivo when you want charts that look considered without designing them, and when you need more than the six chart types a lighter library gives you. It's a good fit for internal dashboards and for editorial charts where a treemap or a sankey is the right answer and you don't want to hand-roll one.

Look elsewhere if your whole need is three bar charts. A single-purpose library, or plain SVG, will cost you less. Nivo's floor is higher than a minimal library's because @nivo/core comes along with whichever family you install.

Key Features

  • Declarative props for every chart family, with the same shape across families
  • SVG and Canvas renderers for the same chart, swappable when point counts grow
  • Server-side rendering for SVG charts, which matters in Next.js and Astro
  • Motion via react-spring, on by default, disabled with animate={false}
  • A theme object that covers axes, grid, labels, tooltips and legends in one place
  • Responsive wrappers (ResponsiveBar, ResponsiveLine) that fill their container

Installation

Install the core plus the families you actually render:

npm install @nivo/core @nivo/bar

React 18 or newer is required. Each additional family is its own install:

npm install @nivo/line @nivo/pie

A Bar Chart

import { ResponsiveBar } from '@nivo/bar';

type Row = { quarter: string; shipped: number; planned: number };

const data: Row[] = [
  { quarter: 'Q1', shipped: 42, planned: 50 },
  { quarter: 'Q2', shipped: 61, planned: 55 },
  { quarter: 'Q3', shipped: 48, planned: 58 },
];

export function ReleaseChart() {
  return (
    <div style={{ height: 320 }}>
      <ResponsiveBar
        data={data}
        keys={['shipped', 'planned']}
        indexBy="quarter"
        groupMode="grouped"
        margin={{ top: 16, right: 16, bottom: 40, left: 48 }}
        axisBottom={{ legend: 'Quarter', legendOffset: 32 }}
        axisLeft={{ legend: 'Features', legendOffset: -40 }}
        colors={{ scheme: 'set2' }}
      />
    </div>
  );
}

The wrapper needs an explicit height. ResponsiveBar measures its parent, and a parent that sizes to its content collapses to zero.

Theming It Once

Define the theme next to your design tokens and pass it to every chart:

const chartTheme = {
  background: 'transparent',
  text: { fontSize: 12, fill: 'var(--color-text)' },
  axis: {
    ticks: { line: { stroke: 'var(--color-border)' } },
    legend: { text: { fontSize: 13 } },
  },
  grid: { line: { stroke: 'var(--color-border)', strokeDasharray: '3 3' } },
  tooltip: { container: { background: 'var(--color-surface)' } },
};

Because it merges with the default, you only write the parts you're changing.

TypeScript Tips

Chart props are generic over your datum type, so type the data and let inference do the rest. Where a prop takes a callback, the datum arrives typed:

<ResponsiveBar<Row>
  data={data}
  keys={['shipped']}
  indexBy="quarter"
  colors={({ data }) => (data.shipped < data.planned ? '#e76f51' : '#2a9d8f')}
/>

Custom layers and tooltips are the two places worth annotating explicitly, since their props are wide unions.

Common Gotchas

The most common one is a chart that renders nothing: the container has no height, so the responsive wrapper measures zero. Give the parent a fixed height or a grid row that resolves.

The second is bundle size creeping up. Each family pulls its own D3 modules, so five families is meaningfully more than one. Check what you're importing before adding a sixth.

The third is animation on large datasets. Motion is on by default and it costs real frames at a few thousand elements. Set animate={false} for dense charts, or move to the Canvas variant.

Frequently Asked Questions

Why does Nivo ship so many separate npm packages?

Every chart family lives in its own package - @nivo/bar, @nivo/line, @nivo/pie and so on - and all of them depend on @nivo/core. You install only the families you render, so a dashboard with bars and lines never pays for the geo or network code. It makes the install list longer and the bundle smaller.

Should I pick the SVG or the Canvas variant?

Start with SVG. Each element is a real DOM node, so you get hover targets, CSS styling and accessibility for free. Switch to the Canvas variant of the same chart once you're drawing several thousand points and the DOM node count starts costing you frames. The props are close enough that swapping is usually a rename.

Does Nivo work with server-side rendering?

The SVG charts do, which is the main reason to pick Nivo over a canvas-only library in a Next.js or Astro app. Canvas charts need a browser and have to be rendered on the client. Nivo also ships an /api endpoint for generating chart images server-side if you need a PNG.

How do I restyle a Nivo chart to match my design system?

Pass a theme object covering axis, grid, labels, tooltip and legends. It merges with the default, so you override only what differs. Colors are separate: the colors prop takes a scheme name, an array, or a function receiving the datum, which is how you bind chart color to your own tokens.