Learn how to create responsive charts in React using Chart.js and react-chartjs-2. Follow this easy step-by-step guide to build a modern chart dashboard.
Want to show your data beautifully in React? Chart.js and React make it simple! With just a few steps, you can create bar charts, pie charts, line charts, and more – all in a clean and modern design. In this guide, we will walk you through building a responsive and attractive chart dashboard using Chart.js and React with react-chartjs-2.
This setup is perfect for developers who want to create visual dashboards, analytics tools, or admin panels.
Setup Environment
Before we dive into the code, let's set up our development environment. Follow these steps:
Step 1: Setup React Project
First, create a new React app:
npx create-react-app react-chartjs-app
cd react-chartjs-app
You can also use Vite if you prefer:
npm create vite@latest react-chartjs-app --template react
cd react-chartjs-app
npm install
Step 2: Install Required Packages
Install Chart.js and its React wrapper:
npm install chart.js react-chartjs-2
Step 3: Run Your App
npm install
npm run dev
Your Vite React app is ready to use.
Step 4: Add Bootstrap 5
You can add Bootstrap by including the CDN in index.html:
<!-- Inside index.html -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
Step-by-Step: Create Chart.js in React
Step 1: Write Chart Component
Replace src/App.jsx with:
import React from 'react';
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend,
PointElement,
LineElement,
ArcElement,
RadialLinearScale,
Filler,
} from 'chart.js';
import { Bar, Line, Pie, Doughnut, Radar } from 'react-chartjs-2';
// Registering all the necessary components for Chart.js
ChartJS.register(
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend,
PointElement,
LineElement,
ArcElement,
RadialLinearScale,
Filler
);
// --- Chart Data & Options ---
// Modern color palette
const modernColors = {
primary: 'rgba(59, 130, 246, 1)',
primaryTransparent: 'rgba(59, 130, 246, 0.1)',
secondary: 'rgba(239, 68, 68, 1)',
secondaryTransparent: 'rgba(239, 68, 68, 0.1)',
tertiary: 'rgba(16, 185, 129, 1)',
tertiaryTransparent: 'rgba(16, 185, 129, 0.2)',
grid: 'rgba(229, 231, 235, 1)',
text: '#374151',
textSecondary: '#6b7280',
};
// --- 1. Line Chart: Website Traffic ---
const lineChartData = {
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'],
datasets: [
{
label: 'Visitors',
data: [65, 59, 80, 81, 56, 55, 62],
fill: true,
backgroundColor: modernColors.primaryTransparent,
borderColor: modernColors.primary,
tension: 0.4,
pointBackgroundColor: modernColors.primary,
pointBorderColor: '#fff',
pointHoverRadius: 7,
pointHoverBackgroundColor: modernColors.primary,
},
],
};
const lineChartOptions = {
responsive: true,
maintainAspectRatio: false,
plugins: { legend: { display: false } },
scales: {
x: { grid: { display: false }, ticks: { color: modernColors.textSecondary } },
y: {
grid: { color: modernColors.grid, borderDash: [2, 4] },
ticks: { color: modernColors.textSecondary, callback: (value) => `${value}k` },
},
},
interaction: { intersect: false, mode: 'index' },
};
// --- 2. Bar Chart: Monthly Sales ---
const barChartData = {
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'],
datasets: [
{
label: 'Sales',
data: [12, 19, 3, 5, 2, 3, 15],
backgroundColor: modernColors.tertiary,
borderWidth: 0,
borderRadius: 6,
barPercentage: 0.6,
categoryPercentage: 0.7,
},
],
};
const barChartOptions = {
responsive: true,
maintainAspectRatio: false,
plugins: { legend: { display: false } },
scales: {
x: { grid: { display: false }, ticks: { color: modernColors.textSecondary } },
y: {
grid: { display: false },
ticks: { color: modernColors.textSecondary, callback: (value) => `$${value}k` },
},
},
};
// --- 3. Pie & Doughnut Charts ---
const pieChartData = {
labels: ['Chrome', 'Firefox', 'Safari', 'Edge'],
datasets: [{
data: [55, 15, 20, 10],
backgroundColor: ['#3B82F6', '#10B981', '#F59E0B', '#6366F1'],
borderColor: '#fff',
borderWidth: 4,
hoverBorderColor: '#fff',
}],
};
const doughnutChartData = { ...pieChartData, labels: ['Desktop', 'Mobile', 'Tablet'] };
const circularChartOptions = (text) => ({
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { display: false },
tooltip: {
callbacks: {
label: (context) => ` ${context.label}: ${context.formattedValue}%`,
},
},
},
cutout: text === 'Device Usage' ? '70%' : '0%',
});
// --- 4. Radar Chart: Skill Assessment ---
const radarChartData = {
labels: ['Problem Solving', 'Communication', 'Teamwork', 'Creativity', 'Leadership', 'Technical'],
datasets: [
{
label: 'Candidate A',
data: [8, 9, 7, 8, 6, 9],
backgroundColor: modernColors.primaryTransparent,
borderColor: modernColors.primary,
borderWidth: 2,
pointBackgroundColor: modernColors.primary,
},
{
label: 'Candidate B',
data: [6, 7, 8, 9, 7, 6],
backgroundColor: modernColors.secondaryTransparent,
borderColor: modernColors.secondary,
borderWidth: 2,
pointBackgroundColor: modernColors.secondary,
},
],
};
const radarChartOptions = {
responsive: true,
maintainAspectRatio: false,
plugins: { legend: { position: 'top', labels: { color: modernColors.text } } },
scales: {
r: {
angleLines: { color: modernColors.grid },
suggestedMin: 0,
suggestedMax: 10,
grid: { color: modernColors.grid },
pointLabels: { font: { size: 12 }, color: modernColors.text },
ticks: { display: false },
}
}
}
// --- Icons (as inline SVGs for self-containment) ---
const icons = {
revenue: <svg className="text-success" width="24" height="24" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4z"></path><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 2v2m0 16v2m8.07-6.93l-1.42 1.42M5.35 18.65l1.42-1.42M22 12h-2m-16 0H2m14.65-6.65l-1.42-1.42M6.77 5.35L5.35 6.77"></path></svg>,
users: <svg className="text-primary" width="24" height="24" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M17 20h5v-2a3 3 0 00-5.356-2.236M12 14a4 4 0 100-8 4 4 0 000 8z"></path><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 15c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path></svg>,
sales: <svg className="text-danger" width="24" height="24" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M3 3v18h18V3H3zm8 14H5V9h6v8zm6 0h-4V5h4v12z"></path></svg>,
performance: <svg className="text-warning" width="24" height="24" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path></svg>,
};
// --- UI Components ---
const StatCard = ({ title, value, change, icon }) => (
<div className="card bg-white border-0 shadow-sm rounded-4 h-100">
<div className="card-body p-4 d-flex">
<div className="flex-grow-1">
<p className="text-muted mb-1 fs-6">{title}</p>
<h4 className="fw-bold mb-0">{value}</h4>
{change && <p className={`mb-0 mt-1 fs-sm ${change.startsWith('+') ? 'text-success' : 'text-danger'}`}>{change}</p>}
</div>
<div className="flex-shrink-0 align-self-center ms-3">
<div className="icon-shape bg-light rounded-circle d-flex align-items-center justify-content-center" style={{ width: '48px', height: '48px' }}>
{icon}
</div>
</div>
</div>
</div>
);
const ChartCard = ({ title, subtitle, children }) => (
<div className="card bg-white border-0 shadow-sm rounded-4 h-100">
<div className="card-header bg-transparent border-0 pt-4 px-4">
<h5 className="card-title fw-bold mb-0">{title}</h5>
<p className="card-text text-muted">{subtitle}</p>
</div>
<div className="card-body p-4">
<div style={{ position: 'relative', height: '300px' }}>{children}</div>
</div>
</div>
);
const CircularChartCard = ({ title, data, options, children }) => (
<div className="card bg-white border-0 shadow-sm rounded-4 h-100">
<div className="card-body p-4 d-flex flex-column">
<h5 className="card-title fw-bold mb-0 text-center">{title}</h5>
<div className="flex-grow-1" style={{ position: 'relative', minHeight: '200px' }}>
{children}
</div>
<div className="mt-3">
{data.labels.map((label, i) => (
<div key={label} className="d-flex align-items-center justify-content-between fs-sm py-1">
<span><span className="d-inline-block rounded-circle me-2" style={{ width: '10px', height: '10px', backgroundColor: data.datasets[0].backgroundColor[i] }}></span>{label}</span>
<span className="fw-bold">{data.datasets[0].data[i]}%</span>
</div>
))}
</div>
</div>
</div>
);
// Main Component
const ChartDashboard = () => {
return (
<div className="container-fluid p-4 p-lg-5" style={{ background: 'linear-gradient(to bottom right, #f8fafc, #f1f5f9)'}}>
<style>{`
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap');
body, .card-title { font-family: 'Inter', sans-serif; color: ${modernColors.text}; }
.card { transition: all 0.3s ease; }
.card:hover { transform: translateY(-5px); box-shadow: 0 0.5rem 1rem rgba(0,0,0,.08)!important; }
.fs-sm { font-size: 0.875rem; }
`}</style>
<div className="mb-4">
<h1 className="fw-bold">Dashboard</h1>
<p className="text-muted">Welcome back, here's a summary of your business.</p>
</div>
<div className="row g-4 mb-4">
<div className="col-lg-3 col-md-6"><StatCard title="Total Revenue" value="$48,329" change="+12.5%" icon={icons.revenue} /></div>
<div className="col-lg-3 col-md-6"><StatCard title="New Users" value="1,204" change="+8.2%" icon={icons.users} /></div>
<div className="col-lg-3 col-md-6"><StatCard title="Total Sales" value="3,450" change="-2.1%" icon={icons.sales} /></div>
<div className="col-lg-3 col-md-6"><StatCard title="Performance" value="92.7%" change="+0.5%" icon={icons.performance} /></div>
</div>
<div className="row g-4">
<div className="col-xl-7">
<ChartCard title="Website Traffic" subtitle="Visitors over the last 7 months (in thousands)">
<Line data={lineChartData} options={lineChartOptions} />
</ChartCard>
</div>
<div className="col-xl-5">
<ChartCard title="Monthly Sales" subtitle="Sales overview (in thousands)">
<Bar data={barChartData} options={barChartOptions} />
</ChartCard>
</div>
<div className="col-lg-4 col-md-6">
<CircularChartCard title="Browser Usage" data={pieChartData}>
<Pie data={pieChartData} options={circularChartOptions('Browser Usage')} />
</CircularChartCard>
</div>
<div className="col-lg-4 col-md-6">
<CircularChartCard title="Device Usage" data={doughnutChartData}>
<Doughnut data={doughnutChartData} options={circularChartOptions('Device Usage')} />
</CircularChartCard>
</div>
<div className="col-lg-4">
<ChartCard title="Skill Assessment" subtitle="Comparison of candidate capabilities">
<Radar data={radarChartData} options={radarChartOptions} />
</ChartCard>
</div>
</div>
</div>
);
};
export default ChartDashboard;
Remove Unused CSS Files (src/assets/App.css & src/assets/Index.css)
Since we're using 100% Bootstrap via CDN, you can safely delete the default App.css and Index.css files to keep your project clean and lightweight.
Run Your App
Go to your terminal:
npm run dev
Open http://localhost:5173/ and see your chart.
Conclusion
Chart.js with React is a powerful combo for building interactive, data-driven dashboards. Whether you're tracking website traffic, showing sales trends, or analyzing user data, you can do it all with clean charts.
Using react-chartjs-2 makes the integration seamless. Combine it with Bootstrap to design a responsive layout that works across all devices.
So, what are you waiting for? Try it now and take your React app to the next level with stunning charts!
That’s a wrap!
I hope you enjoyed this article
Did you like it? Let me know in the comments below 🔥 and you can support me by buying me a coffee.
And don’t forget to sign up to our email newsletter so you can get useful content like this sent right to your inbox!
Thanks!
Faraz 😊
.jpg)
