chart.js vs react-vis vs recharts vs victory-chart
Declarative Charting Libraries for React Applications
chart.jsreact-visrechartsvictory-chartSimilar Packages:

Declarative Charting Libraries for React Applications

chart.js, react-vis, recharts, and victory-chart are popular JavaScript libraries for building data visualizations in web applications. chart.js is a general-purpose canvas-based charting library with a broad feature set and extensive plugin ecosystem. The other three — react-vis, recharts, and victory-chart — are React-specific libraries that embrace declarative composition using JSX. react-vis (developed by Uber) uses SVG and provides low-level primitives for custom visualizations. recharts is also SVG-based and focuses on reusable, composable chart components with strong defaults. victory-chart, part of the Victory suite from Formidable Labs, offers a consistent API across React, React Native, and other renderers, emphasizing themeability and animation. All four support common chart types like line, bar, area, and pie charts, but differ significantly in architecture, customization model, and integration patterns.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
chart.js6,983,85967,1836.18 MB5334 months agoMIT
react-vis08,7932.18 MB3423 years agoMIT
recharts026,7006.38 MB452a month agoMIT
victory-chart011,2661.16 MB90a year agoMIT

Declarative Charting in React: Chart.js vs React-Vis vs Recharts vs Victory

Choosing the right charting library in 2024 isn’t just about drawing lines and bars — it’s about how well the tool fits your architecture, team workflow, and long-term maintainability. Let’s compare these four options through real engineering lenses.

⚠️ Maintenance Status: Don’t Build on Abandoned Foundations

Before diving into features, check project health. react-vis is officially archived by Uber as of late 2022. The GitHub repo shows “This repository has been archived by the owner. It is now read-only.” The npm page includes a deprecation notice recommending alternatives. Do not use react-vis in new projects.

The other three — chart.js, recharts, and victory-chart — are actively maintained with recent releases and responsive issue tracking.

🧱 Architecture: Imperative Canvas vs Declarative SVG

chart.js: Imperative, Canvas-Based

chart.js renders to HTML <canvas>, giving it high performance for large datasets but limiting direct DOM access. You configure charts via JavaScript objects, not JSX.

// chart.js: imperative setup
import { Chart, registerables } from 'chart.js';
Chart.register(...registerables);

const ctx = document.getElementById('myChart');
new Chart(ctx, {
  type: 'line',
  data: {
    labels: ['Jan', 'Feb', 'Mar'],
    datasets: [{
      label: 'Sales',
      data: [12, 19, 3],
      borderColor: 'rgb(75, 192, 192)'
    }]
  },
  options: { responsive: true }
});

In React, you’d typically wrap this in a useEffect hook, which breaks React’s declarative flow.

recharts & victory-chart: Declarative, SVG-Based

Both use SVG and embrace React’s component model. You compose charts like any other UI.

// recharts: fully declarative
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip } from 'recharts';

const data = [{ name: 'Jan', sales: 12 }, { name: 'Feb', sales: 19 }];

<LineChart width={500} height={300} data={data}>
  <CartesianGrid strokeDasharray="3 3" />
  <XAxis dataKey="name" />
  <YAxis />
  <Tooltip />
  <Line type="monotone" dataKey="sales" stroke="#8884d8" />
</LineChart>
// victory-chart: similar declarative style
import { VictoryLine, VictoryChart, VictoryAxis, VictoryTooltip } from 'victory';

const data = [{ x: 'Jan', y: 12 }, { x: 'Feb', y: 19 }];

<VictoryChart>
  <VictoryAxis />
  <VictoryAxis dependentAxis />
  <VictoryLine data={data} labelComponent={<VictoryTooltip />} />
</VictoryChart>

This approach integrates naturally with React state, props, and hooks — no refs or side effects needed.

🎨 Customization: Configuration vs Composition

chart.js: Deep Configuration, Shallow Composition

Customization happens through nested config objects. Want a custom tooltip? You write a function that returns HTML strings.

// chart.js tooltip callback
options: {
  plugins: {
    tooltip: {
      callbacks: {
        label: (context) => `$${context.parsed.y}`
      }
    }
  }
}

This works but feels disconnected from React’s component model.

recharts: Composable Components

Everything is a component. Need a custom tooltip? Pass a React element.

// recharts custom tooltip
const CustomTooltip = ({ active, payload }) => {
  if (active && payload && payload.length) {
    return <div className="custom-tooltip">${payload[0].value}</div>;
  }
  return null;
};

<LineChart ...>
  <Tooltip content={<CustomTooltip />} />
</LineChart>

Same for axes, legends, and even data points — all swappable via JSX.

victory-chart: Props-Driven with Render Props

Victory uses a mix of props and render functions. Custom tooltips use the labelComponent prop:

// victory custom tooltip
const CustomTooltip = (props) => (
  <VictoryTooltip {...props} label={`${props.datum.y}`} />
);

<VictoryLine data={data} labelComponent={<CustomTooltip />} />

It also supports functional components via dataComponent, containerComponent, etc., offering flexibility without full JSX composition.

📱 Responsiveness and Performance

chart.js

Responsive by default (options.responsive: true), but canvas redraws can cause layout thrashing if not debounced. Large datasets (>10k points) perform well due to canvas rendering.

recharts

Fully responsive via percentage-based dimensions or ResponsiveContainer. Since it uses SVG, performance degrades with very large datasets — but it includes optimizations like syncId for linked charts and lazy rendering for tooltips.

// recharts responsive wrapper
import { ResponsiveContainer } from 'recharts';

<ResponsiveContainer width="100%" height={400}>
  <LineChart data={data}>...</LineChart>
</ResponsiveContainer>

victory-chart

Also responsive by default. Uses D3 under the hood for scale calculations but renders SVG. Includes built-in debouncing for resize events. Animation is enabled by default, which can impact performance if not managed.

🔌 Interactivity and Events

All libraries support hover, click, and zoom, but the APIs differ.

chart.js

Uses event hooks in config:

options: {
  onClick: (event, elements) => {
    if (elements.length > 0) {
      const index = elements[0].index;
      console.log(data[index]);
    }
  }
}

recharts

Pass event handlers as props to components:

<Line
  dataKey="sales"
  onClick={(data, index) => console.log(data)}
/>

victory-chart

Uses consistent event props across components:

<VictoryLine
  data={data}
  events={[{
    target: "data",
    eventHandlers: {
      onClick: () => ({ mutation: () => console.log("clicked") })
    }
  }]}
/>

Victory’s event system is powerful but has a steeper learning curve.

🔄 Data Format Expectations

  • chart.js: Expects { labels: string[], datasets: { data: number[] }[] }
  • recharts: Works with flat arrays of objects: [{ name: 'Jan', value: 12 }]
  • victory-chart: Prefers { x, y } objects or arrays: [{ x: 'Jan', y: 12 }]

recharts’ format aligns best with typical REST API responses, reducing transformation overhead.

🧪 Testing and Debugging

  • chart.js: Harder to unit test because it manipulates canvas outside React’s virtual DOM.
  • recharts & victory-chart: Easy to snapshot test with React Testing Library since they render standard SVG elements.
// Example test for recharts
render(
  <LineChart data={testData}>
    <Line dataKey="value" />
  </LineChart>
);
expect(screen.getByText('12')).toBeInTheDocument();

📊 Summary: When to Use Which

Concernchart.jsreact-visrechartsvictory-chart
Maintenance✅ Active❌ Archived / Deprecated✅ Active✅ Active
React Integration⚠️ Imperative wrapper needed✅ Declarative (but dead)✅ Fully native JSX✅ JSX with props
Performance (Large Data)✅ Canvas scales well✅ SVG (but unmaintained)⚠️ SVG struggles >5k points⚠️ Similar SVG limits
Customization⚙️ Config-heavy🧩 Low-level SVG control🧱 Component composition🎭 Props + render functions
Responsiveness✅ Built-in✅ ManualResponsiveContainer✅ Default behavior
Learning CurveMediumHigh (and obsolete)LowMedium

💡 Final Recommendation

  • Avoid react-vis entirely — it’s deprecated and poses long-term risk.
  • Use chart.js only if you need canvas-level performance, work outside React, or depend on its plugin ecosystem (e.g., chartjs-plugin-zoom).
  • Prefer recharts for most React applications — it offers the best balance of simplicity, composability, and TypeScript support.
  • Choose victory-chart if you’re already using Victory for other visualizations, need React Native compatibility, or want opinionated theming and animations.

In practice, recharts has become the go-to for React teams who want charts that feel like first-class React citizens — and for good reason.

How to Choose: chart.js vs react-vis vs recharts vs victory-chart

  • chart.js:

    Choose chart.js if you need a mature, highly customizable charting solution that works outside React or when you require advanced features like zoom, pan, or annotation plugins. It’s ideal when you’re okay managing imperative APIs or wrapping it in a React component yourself. Avoid it if you prefer a fully declarative, JSX-native approach or need tight integration with React state without extra abstraction layers.

  • react-vis:

    Choose react-vis if you're building complex, custom visualizations that go beyond standard chart types and need fine-grained control over SVG elements. It’s well-suited for dashboards requiring bespoke interaction logic or novel visual encodings. However, note that as of 2023, Uber has archived the repository and marked it as unmaintained — so avoid it for new projects unless you can commit to long-term maintenance.

  • recharts:

    Choose recharts if you want a modern, declarative charting library built specifically for React with excellent TypeScript support, responsive design, and smooth animations out of the box. It shines in applications where charts are composed from reusable parts (e.g., shared axes, tooltips, legends) and where developer experience matters. It’s a strong default choice for most React-based data dashboards.

  • victory-chart:

    Choose victory-chart if you need cross-platform consistency (e.g., sharing chart logic between web and React Native) or if your design system relies heavily on theming and animated transitions. Its uniform API across chart types simplifies code reuse, and its event system supports rich interactivity. It’s particularly effective when you value convention over configuration and want animations enabled by default.

README for chart.js

https://www.chartjs.org/
Simple yet flexible JavaScript charting for designers & developers

Downloads GitHub Workflow Status Coverage Awesome Discord

Documentation

All the links point to the new version 4 of the lib.

In case you are looking for an older version of the docs, you will have to specify the specific version in the url like this: https://www.chartjs.org/docs/2.9.4/

Contributing

Instructions on building and testing Chart.js can be found in the documentation. Before submitting an issue or a pull request, please take a moment to look over the contributing guidelines first. For support, please post questions on Stack Overflow with the chart.js tag.

License

Chart.js is available under the MIT license.