Visualizing data with React and Chart.js
If you want to display basic charts in your React app or create a simple report for the web, Chart.js would arguably be the most straightforward and convenient option.
Chart.js was created in 2013 and, since then, never stopped evolving with the great support of its community (> 60k Github stars and > 2.5m weekly npm downloads).
Developers like Chart.js for its simple API, framework support (including React), built-in Typescript typings, excellent performance with Canvas rendering, and open-sourced MIT-licenced codebase.
Installation
For this tutorial, we’ll use Create React App with Typescript to get us started.
npx create-react-app my-app — template typescript && cd react-chartjs-demo
Now we need to add two libraries: chart.js for charts and react-chartjs-2 to wrap the former in ready-to-use React components.
npm install chart.js react-chartjs-2
React Chart.js components
In order to display charts with Chart.js, we’re using React components from the react-chartjs-2 library. It allows us to select a chart type we want to use and accepts data as props alongside the chart options like colors, scale, etc.
See the full props documentation of Chart component on their official website.
Data is being passed via data prop, which takes in an object similar to the one below.
const data = {
labels: ['January', 'February', 'March', 'April', 'May', 'June'],
datasets: [{
label: 'Average temperature in Celsius',
data: [7, 5, 12, 14, 21, 25]
}]
}
Data
We need some input to display in our charts, and now that we know how the data prop is structured, we can easily create some random data for it.
For this tutorial, we will use a set of utility functions to generate two types of random data: one fits better for visual comparison and the other for visual distribution.
The data format matches the official props format described in the previous section.
// utils.ts
export const MONTHS = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
];
export const COLORS = [
'#4dc9f6',
'#f67019',
'#f53794',
'#537bc4',
'#acc236',
'#166a8f',
'#00a950',
'#58595b',
'#8549ba'
];
export const AGES = [20, 25, 30, 35, 40, 45, 50, 55, 60, 65];
function generateRandomIntegerInRange(min: number, max: number) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
/*
Generates comparable Chart.js data
*/
export function generateSalesChartData() {
return {
labels: MONTHS,
datasets: [{
label: 'Sales',
backgroundColor: COLORS[generateRandomIntegerInRange(0, COLORS.length)],
data: MONTHS.map(d => generateRandomIntegerInRange(10, 100))
}]
};
};
/*
Generates distributed Chart.js data
*/
export function generateSalaryChartData() {
const baseSalary = 40000;
let salary = baseSalary;
return {
datasets: [{
label: 'Age / Average Salary',
backgroundColor: COLORS[generateRandomIntegerInRange(0, COLORS.length)],
data: AGES.map((age, i) => {
salary = age < 45 ? Math.floor(salary + 20000 * Math.random()) : Math.floor(salary - 20000 * Math.random());
return { x: age, y: salary, r: (salary / baseSalary) * 5 }
})
}]
};
};
If you need to fetch your data via the network, refer to the Data Fetching section of React docs.
Boilerplate
Let’s add come boilerplate code in order to prepare our future charts. First, we need to import all necessary components and utility functions.
ChartJs is tree-shakable. It means that we need to import and register all ChartJs components we want to use. Only things that we register will be included in the app bundle.
// App.tsx
import React from 'react';
import './App.css';
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
PointElement,
LineElement,
ArcElement,
Title,
Tooltip,
Legend,
BarElement,
} from 'chart.js';
import { generateSalesChartData, generateSalaryChartData } from './utils';
ChartJS.register(
CategoryScale,
LinearScale,
PointElement,
LineElement,
BarElement,
ArcElement,
Title,
Tooltip,
Legend
);
const comparableChartData = generateSalesChartData();
const distributedChartData = generateSalaryChartData();
export default function App() {
return (
<div className="app">
<h2>Visualising data comparison</h2>
<>...</>
<h2>Visualising data distribution</h2>
<>...</>
</div>
);
}
Let’s remove everything from App.css and add the following styles.
/* App.css */
.app {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
row-gap: 20px;
}
.chart-container {
min-width: 480px;
}
Visualising data comparison
Let’s start by creating a simple Bar Chart component. We’ll use options to set the legend position and display a chart title.
// components/BarChart.tsx
import React from "react";
import { Bar } from "react-chartjs-2";
import { ChartData } from 'chart.js';
const options = {
plugins: {
legend: {
position: 'top' as const,
},
title: {
display: true,
text: 'Bar Chart',
},
},
};
export function BarChart({ data }: { data: ChartData<'bar'> }): JSX.Element {
return (
<div className="chart-container">
<Bar
data={data}
options={options}
/>
</div>
);
}
Similar to Bar, let’s create a Line component. We only make one change to the options setting the y scale to always begin at zero.
// components/LineChart.tsx
import React from "react";
import { Line } from "react-chartjs-2";
import { ChartData } from 'chart.js';
const options = {
plugins: {
legend: {
position: 'top' as const,
},
title: {
display: true,
text: 'Line Chart',
}
},
scales: {
y: {
beginAtZero: true
}
}
};
export function LineChart({ data }: { data: ChartData<'line'> }): JSX.Element {
return (
<div className="chart-container">
<Line
data={data}
options={options}
/>
</div>
);
}
The last addition to the comparison category is a Pie chart.
// components/PieChart.tsx
import React from "react";
import { Pie } from "react-chartjs-2";
import { ChartData } from 'chart.js';
const options = {
plugins: {
legend: {
position: 'bottom' as const,
},
title: {
display: true,
text: 'Pie Chart',
},
},
};
export function PieChart({ data }: { data: ChartData<'pie'> }): JSX.Element {
return (
<div className="chart-container">
<Pie
data={data}
options={options}
/>
</div>
);
}
Visualising data distribution
A scatter chart is, without a doubt, one of the best ones to visualize the distribution of data. Let’s create a ScatterChart React component.
We also limit the max value of the chart’s y-axis via the options prop.
// components/ScatterChart.tsx
import React from "react";
import { Scatter } from "react-chartjs-2";
import { ChartData } from 'chart.js';
const options = {
plugins: {
legend: {
position: 'bottom' as const,
},
title: {
display: true,
text: 'Scatter Chart',
},
},
scales: {
y: {
max: 120000,
}
}
};
export function ScatterChart({ data }: { data: ChartData<'scatter'> }): JSX.Element {
return (
<div className="chart-container">
<Scatter
data={data}
options={options}
/>
</div>
);
}
Similar to the one above, BubbleChart gets the y-axis limit, and also, we’re disabling mouse events on the chart by setting the events property to an empty array.
// components/BubbleChart.tsx
import React from "react";
import { Bubble } from "react-chartjs-2";
import { ChartData } from 'chart.js';
const options = {
plugins: {
legend: {
position: 'bottom' as const,
},
title: {
display: true,
text: 'Bubble Chart',
}
},
scales: {
y: {
max: 120000,
}
},
events: []
};
export function BubbleChart({ data }: { data: ChartData<'bubble'> }): JSX.Element {
return (
<div className="chart-container">
<Bubble
data={data}
options={options}
/>
</div>
);
}
Final results
Lastly, we’re putting everything together by updating the App.tsx: adding chart components on the page, and passing the data properties to them. The Pie chart additionally gets a data update with more colorful backgrounds.
// App.tsx
import React from 'react';
import './App.css';
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
PointElement,
LineElement,
ArcElement,
Title,
Tooltip,
Legend,
BarElement,
} from 'chart.js';
import { COLORS, generateSalesChartData, generateSalaryChartData } from './utils';
import { LineChart } from './components/LineChart'
import { BarChart } from './components/BarChart'
import { PieChart } from './components/PieChart';
import { ScatterChart } from './components/ScatterChart';
import { BubbleChart } from './components/BubbleChart';
ChartJS.register(
CategoryScale,
LinearScale,
PointElement,
LineElement,
BarElement,
ArcElement,
Title,
Tooltip,
Legend
);
const comparableChartData = generateSalesChartData();
const distributedChartData = generateSalaryChartData();
export default function App() {
return (
<div className="app">
<h2>Visualising data comparison</h2>
<LineChart
data={comparableChartData}
/>
<BarChart
data={comparableChartData}
/>
<PieChart
data={{ ...comparableChartData, datasets: comparableChartData.datasets.map(d => ({ ...d, backgroundColor: COLORS })) }}
/>
<h2>Visualising data distribution</h2>
<ScatterChart
data={distributedChartData}
/>
<BubbleChart
data={distributedChartData}
/>
</div>
);
}
Conclusion
ChartJs is a powerful yet simple to use library to visualise your data in React. Continue your journey by exploring the official ChartJs website and its wrapper for React react-chartjs-2.
The source code for this tutorial can be found on the Github repository. You can also see it live via this Repl.