Skip to main content
Technology & EngineeringData Visualization163 lines

Nivo

Expert guidance for building rich, themed data visualizations in React with Nivo

Quick Summary21 lines
You are an expert in creating data visualizations with Nivo.

## Key Points

- **Canvas Rendering**: Use `BarCanvas`, `LineCanvas`, etc. for high-performance rendering of large datasets (thousands of data points).
- **Animations**: Powered by React Spring; configure via `animate` and `motionConfig` props.
- **Custom Layers**: Add custom SVG/Canvas layers via the `layers` prop to overlay annotations or custom drawings.
- **Server-Side Rendering**: Nivo provides `@nivo/static` for generating chart images on the server and an API service for on-demand chart generation.
- Always wrap Responsive* components in a parent div with an explicit height; the component fills its parent.
- Use the `colors` prop with a `{ scheme: "..." }` object to leverage D3 color schemes consistently across charts.
- Switch to Canvas variants (`BarCanvas`, `LineCanvas`) when rendering more than a few hundred data points to maintain performance.
- Not setting a height on the wrapper div, which causes Responsive* components to render with zero height and appear invisible.
- Passing data in the wrong shape; each chart type expects a specific structure (e.g., `@nivo/line` expects `{ id, data: [{ x, y }] }` arrays, not flat arrays).

## Quick Example

```bash
npm install @nivo/bar @nivo/line @nivo/pie
```
skilldb get data-visualization-skills/NivoFull skill: 163 lines
Paste into your CLAUDE.md or agent config

Nivo — Data Visualization

You are an expert in creating data visualizations with Nivo.

Overview

Nivo is a rich set of data visualization components for React, built on top of D3. It provides high-level, fully featured chart components with built-in theming, animations (via React Spring), and interactivity. Nivo supports SVG, Canvas, and HTML rendering, and offers server-side rendering support. Use Nivo when you want polished, interactive charts in React with minimal configuration and strong theming capabilities.

Setup & Configuration

Install the specific chart package you need:

npm install @nivo/bar @nivo/line @nivo/pie

Basic bar chart:

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

const data = [
  { country: "US", sales: 120 },
  { country: "UK", sales: 80 },
  { country: "DE", sales: 95 },
];

function SalesBar() {
  return (
    <div style={{ height: 400 }}>
      <ResponsiveBar
        data={data}
        keys={["sales"]}
        indexBy="country"
        margin={{ top: 50, right: 50, bottom: 50, left: 60 }}
        padding={0.3}
        colors={{ scheme: "nivo" }}
        axisBottom={{ legend: "Country", legendPosition: "middle", legendOffset: 36 }}
        axisLeft={{ legend: "Sales", legendPosition: "middle", legendOffset: -40 }}
        labelSkipWidth={12}
        animate={true}
      />
    </div>
  );
}

Core Patterns

Line Chart

import { ResponsiveLine } from "@nivo/line";

const data = [
  {
    id: "revenue",
    data: [
      { x: "Jan", y: 100 },
      { x: "Feb", y: 120 },
      { x: "Mar", y: 90 },
    ],
  },
];

<div style={{ height: 400 }}>
  <ResponsiveLine
    data={data}
    margin={{ top: 20, right: 20, bottom: 50, left: 60 }}
    xScale={{ type: "point" }}
    yScale={{ type: "linear", min: "auto", max: "auto" }}
    curve="monotoneX"
    enablePoints={true}
    pointSize={8}
    useMesh={true}
  />
</div>

Pie Chart

import { ResponsivePie } from "@nivo/pie";

const data = [
  { id: "css", label: "CSS", value: 30 },
  { id: "js", label: "JavaScript", value: 50 },
  { id: "html", label: "HTML", value: 20 },
];

<div style={{ height: 400 }}>
  <ResponsivePie
    data={data}
    margin={{ top: 40, right: 80, bottom: 80, left: 80 }}
    innerRadius={0.5}
    padAngle={0.7}
    cornerRadius={3}
    activeOuterRadiusOffset={8}
    colors={{ scheme: "paired" }}
  />
</div>

Theming

const customTheme = {
  background: "#ffffff",
  text: { fontSize: 12, fill: "#333333" },
  axis: {
    ticks: { text: { fontSize: 11, fill: "#555555" } },
    legend: { text: { fontSize: 13, fontWeight: "bold" } },
  },
  grid: { line: { stroke: "#dddddd" } },
};

<ResponsiveBar theme={customTheme} /* ... */ />

Advanced Features

  • Canvas Rendering: Use BarCanvas, LineCanvas, etc. for high-performance rendering of large datasets (thousands of data points).
  • Animations: Powered by React Spring; configure via animate and motionConfig props.
  • Custom Layers: Add custom SVG/Canvas layers via the layers prop to overlay annotations or custom drawings.
  • Server-Side Rendering: Nivo provides @nivo/static for generating chart images on the server and an API service for on-demand chart generation.

Best Practices

  • Always wrap Responsive* components in a parent div with an explicit height; the component fills its parent.
  • Use the colors prop with a { scheme: "..." } object to leverage D3 color schemes consistently across charts.
  • Switch to Canvas variants (BarCanvas, LineCanvas) when rendering more than a few hundred data points to maintain performance.

Core Philosophy

Nivo occupies a deliberate middle ground in the React visualization spectrum: more opinionated and feature-complete than visx, less low-level than raw D3, but more customizable than Recharts. Its design principle is that a chart component should be a self-contained unit that handles theming, animation, interactivity, and accessibility out of the box, while still exposing enough props and layer hooks for meaningful customization. If you find yourself fighting Nivo to achieve a visual effect, you may need visx; if you find Nivo's prop surface overwhelming, you may want Recharts.

Theming is a first-class concept. Nivo's theme object propagates consistently across all chart types, ensuring that font sizes, colors, grid styles, and label formatting are uniform without per-chart configuration. Investing time in defining a theme object upfront -- one that matches your application's design system -- eliminates repetitive prop-setting and guarantees visual coherence across a dashboard of mixed chart types.

The responsive wrapper pattern (ResponsiveBar, ResponsiveLine, etc.) is the intended API. These components measure their parent container and pass width and height to the chart automatically. But this only works if the parent has an explicit height. A common frustration with Nivo -- charts rendering with zero height -- stems from not understanding that CSS block elements have no intrinsic height. The wrapper div needs a defined height, either via explicit CSS or a layout system like flexbox or grid.

Anti-Patterns

  • No height on the wrapper div: Wrapping a ResponsiveBar or ResponsiveLine in a <div> without setting a height. The responsive component fills its parent, so a parent with zero height produces an invisible chart. Always set an explicit height on the container.

  • Wrong data shape for the chart type: Passing flat arrays to @nivo/line (which expects { id, data: [{ x, y }] }) or nested objects to @nivo/bar (which expects flat arrays with an index key). Each Nivo chart has a specific data contract; violating it produces cryptic errors or empty renders.

  • Using SVG variants for large datasets: Rendering 5,000 data points with ResponsiveBar (SVG) instead of BarCanvas. SVG creates a DOM node per data point, which degrades rendering performance and interaction responsiveness. Switch to Canvas variants above a few hundred points.

  • Over-customizing with inline styles instead of themes: Passing individual color, font, and spacing props on every chart component instead of defining a shared theme object. This leads to inconsistent styling across charts and makes global design changes tedious.

  • Ignoring animation performance on dashboards: Leaving animate={true} (the default) on charts that update frequently via polling or real-time data. Each update triggers a spring animation, causing visual jitter. Set animate={false} or use short motionConfig values for frequently updating charts.

Common Pitfalls

  • Not setting a height on the wrapper div, which causes Responsive* components to render with zero height and appear invisible.
  • Passing data in the wrong shape; each chart type expects a specific structure (e.g., @nivo/line expects { id, data: [{ x, y }] } arrays, not flat arrays).

Install this skill directly: skilldb add data-visualization-skills

Get CLI access →