Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For most React applications, the reliable way to create a graph is to install a chart library and render the graph as a component. Recharts is the most direct beginner path because its chart parts are React components. If your team already uses the Chart.js configuration model, use Chart.js through react-chartjs-2.

This guide builds a working line graph, explains the data shape and responsive layout, shows the Chart.js alternative, and covers updates, accessibility, performance, and common failures.

Choose a React graph library first

Do not start by drawing lines with ad-hoc DOM code. A chart library handles scales, axes, tooltips, resizing, and interaction while React controls when the chart receives new data.

Need Starting point Why
A declarative graph assembled from React components Recharts The project describes a composable charting library built on React components, with SVG rendering.
The Chart.js ecosystem or its labels-and-datasets configuration Chart.js with react-chartjs-2 The wrapper supplies React components while Chart.js supplies the chart implementation.
A smaller Chart.js feature set Chart.js with explicit registration You import and register only the controllers, elements, scales, and plugins you use.

Neither source establishes a universal speed winner. Choose by chart types, interactions, accessibility behavior, rendering format, bundle goals, and compatibility with the rest of your application.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Build a line graph with Recharts

1. Install the package

In an existing React project, run:

npm install recharts

The official guide identifies npm as the easiest and fastest start for a single-page application. The Recharts project site displayed version 3.10.1 when checked on September 29, 2026; package versions change, so use the version resolved by your lockfile and review its current documentation when upgrading.

2. Add a component with data, axes, and a series

import {
  CartesianGrid,
  Line,
  LineChart,
  ResponsiveContainer,
  Tooltip,
  XAxis,
  YAxis,
} from 'recharts';

const data = [
  { month: 'Jan', visits: 120 },
  { month: 'Feb', visits: 180 },
  { month: 'Mar', visits: 150 },
];

export function VisitsGraph() {
  return (
    <div style={{ width: '100%', height: 300 }}>
      <ResponsiveContainer>
        <LineChart data={data}>
          <CartesianGrid strokeDasharray='3 3' />
          <XAxis dataKey='month' />
          <YAxis />
          <Tooltip />
          <Line type='monotone' dataKey='visits' stroke='#2563eb' />
        </LineChart>
      </ResponsiveContainer>
    </div>
  );
}

The outer div deliberately supplies a height. ResponsiveContainer can calculate width from its parent, but it cannot invent a useful height when every ancestor has an automatic height.

3. Understand the mapping

  • data is an array of records. Each record has a category field (month) and a numeric field (visits).
  • dataKey tells a chart part which property to read. The X axis reads month; the line reads visits.
  • XAxis and YAxis provide context for the values.
  • CartesianGrid makes horizontal and vertical comparisons easier.
  • Tooltip reveals the values at a hovered point.
  • Line maps the selected numeric field to a visual series.

Give the graph a visible heading in the surrounding page, and provide the underlying values as text or a table when readers need to inspect exact numbers or cannot use the visual interaction.

Use live or changing data safely

Keep the API response in the chart’s shape

Transform server data before rendering rather than scattering conversion logic through chart props. For example, map an API response into objects with stable keys:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const chartData = apiRows.map((row) => ({
  month: row.periodLabel,
  visits: Number(row.visitCount),
}));

Reject or flag values that are not finite numbers. A string that happens to contain digits may not behave like a numeric value in every scale or formatter.

Show loading, error, and empty states

Do not render an empty frame while a request is pending and call it zero. Use a loading message, an error message with a retry action, and a specific empty-state explanation when the response contains no records. Missing measurements should remain distinguishable from a measured zero; represent them according to the API contract and explain the gap in nearby text.

Update without remounting the page

When a filter, date range, or polling cycle changes, update the state holding the data array. Keep a stable component structure so tooltips and keyboard focus do not reset unnecessarily. If you render several series, give each series its own numeric property and a clear label or legend entry.

Common Recharts customizations

Multiple lines

Add another Line with a different dataKey and stroke color. Both series must use compatible records; if one series has no value for a category, decide how the gap should be communicated rather than silently treating it as zero.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Bars, areas, and combinations

Recharts composes charts from parts, so a bar graph replaces or supplements Line with a bar series, while an area graph uses an area series. Keep the same principles: a category key for the horizontal axis, numeric keys for series, and a defined parent size.

Tooltips and formatting

Format dates, currency, and large numbers for the reader instead of exposing raw database values. A tooltip is supplementary; retain a title, axis labels where needed, and a non-visual representation for critical results.

Chart.js in React with react-chartjs-2

Install both packages

npm install --save chart.js react-chartjs-2

The wrapper quickstart recommends Chart.js 4 and also documents support for Chart.js 3. Check the wrapper’s current peer-dependency requirements and migration guide before changing either package.

Register the pieces used by the graph

import {
  CategoryScale,
  Chart as ChartJS,
  LinearScale,
  LineElement,
  PointElement,
  Tooltip,
} from 'chart.js';
import { Line } from 'react-chartjs-2';

ChartJS.register(
  CategoryScale,
  LinearScale,
  LineElement,
  PointElement,
  Tooltip,
);

const data = {
  labels: ['Jan', 'Feb', 'Mar'],
  datasets: [
    {
      label: 'Visits',
      data: [120, 180, 150],
      borderColor: '#2563eb',
    },
  ],
};

export function VisitsGraph() {
  return <Line data={data} />;
}

Chart.js is tree-shakeable. Selective imports require registering every controller, element, scale, and plugin that your selected chart needs. For a deliberately simple setup, the integration documentation describes importing chart.js/auto; that shortcut enables all features and can include more code than a selective registration.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Translate the data model

Recharts reads fields from records through dataKey. Chart.js separates category labels from series values: labels is the horizontal sequence, and each dataset has its own data array. Keep the two arrays aligned and use one dataset per series.

Layout, accessibility, and production details

Make resizing predictable

  • Give the chart container a deliberate height or aspect ratio.
  • Use a width of 100 percent inside responsive cards and grids.
  • Test narrow mobile widths, wide desktop layouts, and browser zoom.
  • Do not rely on hover alone to expose important values.

Make the graph understandable without sighted hover interaction

Use a meaningful heading such as “Monthly visits, January–March 2026,” state the unit, and explain the time range. Include a text summary or table for exact values. Use color combinations with sufficient contrast and do not encode the only distinction between series by color.

Keep rendering work proportional to the data

Reduce or aggregate very dense data before sending it to the browser when the display cannot show every point. Avoid recreating large transformed arrays on every unrelated render; memoize transformations when profiling shows that they matter. These are workload-dependent engineering choices, not a claim that one library is always faster.

Plan for server rendering and responsive measurement

Charts that measure the browser container need a client-side layout. If your framework renders HTML on the server, isolate the chart in the client-rendered portion and verify that the initial markup does not depend on a browser-only measurement. Test hydration and resize behavior in the framework version you deploy.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Troubleshooting

The chart is blank or has zero height

Inspect the immediate parent of ResponsiveContainer. Add an explicit height, confirm that no ancestor is collapsed, and check that the component is actually mounted. A percentage height only works when the containing block has a resolved height.

“ is not a registered scale” or a similar Chart.js error

Register the missing scale, controller, element, or plugin with ChartJS.register(...). If you intentionally prefer the simple route, replace selective imports with chart.js/auto and accept its broader feature bundle.

Points or bars do not appear

Log one record immediately before rendering. Confirm that the property named by each dataKey exists, numeric values are finite, and labels and datasets have matching lengths in Chart.js. Check for a case mismatch such as Visits versus visits.

The graph shows the wrong values after filtering

Verify that the filter updates the state used by the chart and that your transformation does not mutate the original response. Give each request a clear loading and error path so an older response cannot overwrite a newer selection.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The graph works locally but fails after deployment

Check the production build for the same package versions recorded in the lockfile, confirm that client-only chart code is loaded in the browser, and inspect the deployed page’s console for missing registrations, blocked assets, or a container whose CSS differs from development.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your immediate task is documenting or sharing the finished React graph, ScreenshotNeo can capture the page through one API request instead of requiring a local browser automation script. It accepts consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before the capture; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the page verdict and billing status in X-Page-Verdict and X-Billed headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.

See the ScreenshotNeo API documentation for the current parameter list. This call captures a deployed dashboard or graph page; it does not replace the React chart component:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://your-app.example.com/dashboard -o graph.webp

The same request from Python:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://your-app.example.com/dashboard"}, timeout=90)
open("graph.webp", "wb").write(r.content)

And from Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://your-app.example.com/dashboard' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo supports PNG, JPEG, WebP, and PDF output, along with full-page capture, element selectors, device presets, custom viewport and retina scale, dark mode, waits, custom CSS and JavaScript, request blocking, headers and cookies, geolocation and timezone, signed links, asynchronous jobs, bulk capture of up to 100 URLs per call, caching with a chosen TTL, and a usage API. Every feature is on every plan: 1,000 screenshots per month are free with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account to try it.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Why does ResponsiveContainer need a fixed height?

It measures the available parent box. A parent with no resolved height gives the responsive chart no vertical space, so set a height or aspect ratio on the container.

Is chart.js/auto appropriate for every production build?

It is the documented shortcut when simplicity matters, but selective registration imports only the features you use and may better fit a bundle-sensitive application.

How should a graph represent missing measurements?

Keep missing values distinct from measured zero, document the gap near the graph, and choose the library’s gap behavior deliberately instead of silently inventing data.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.