In this post i am going to write how i create a Dashboard with react,tailwind,recharts,tanstack table.
See If you want to create a Dashboard or want to learn how to create one this is a perfect post for you.
live project link
https://eclectic-crostata-422732.netlify.app/
This is publish in netlify cannot say how long it will active because it on free tier
code link (github link)
https://github.com/naviny058/dashb
Table with TanStack Table
Let me tell you one thing that Dashboard are everywhere for eg :- for Admin - Admin Dashboard,User - User Dashboard, Manager - Manger Dashboard.
Suppose their are lot's of info like All Products, Total Orders,Active User, Daily sales. and for checking those data you are visited differenct page but what if all those data came under one roof what if you can see them in chart or graph or some kind of table isn't it amazing. this problem solve dashboard. So let's create one.
First of all setup your react app with help of vite and also install tailwind. Don't worry this is not a big task you can easily go to tailwind website and search setup with vite react and you can go.
Tech we will use
- Recharts for Displaying Charts
- tanstack-table for Displaying Table
- React Router for Navigation
So for implementing Dashboard we need some data that data comes from backend or mock data we are going to use data just copy paste this
{
"stats": {
"totalUsers": 12450,
"activeUsers": 3890,
"monthlyRevenue": 842300,
"conversionRate": 3.8,
"growth": {
"users": 12.4,
"revenue": 8.9,
"orders": -2.1
}
},
"revenueOverTime": [
{ "month": "Jan", "revenue": 52000 },
{ "month": "Feb", "revenue": 61000 },
{ "month": "Mar", "revenue": 58000 },
{ "month": "Apr", "revenue": 72000 },
{ "month": "May", "revenue": 81000 },
{ "month": "Jun", "revenue": 95000 },
{ "month": "Jul", "revenue": 102000 },
{ "month": "Aug", "revenue": 110000 }
],
"usersOverTime": [
{ "date": "2025-01-01", "users": 1200 },
{ "date": "2025-02-01", "users": 1800 },
{ "date": "2025-03-01", "users": 2600 },
{ "date": "2025-04-01", "users": 3400 },
{ "date": "2025-05-01", "users": 4200 },
{ "date": "2025-06-01", "users": 5100 }
],
"revenueByCategory": [
{ "category": "Subscriptions", "value": 55 },
{ "category": "One-time Purchases", "value": 25 },
{ "category": "Ads", "value": 15 },
{ "category": "Affiliates", "value": 5 }
],
"trafficSources": [
{ "source": "Organic", "visits": 4200 },
{ "source": "Paid Ads", "visits": 2800 },
{ "source": "Social Media", "visits": 1900 },
{ "source": "Referral", "visits": 1100 }
],
"recentOrders": [
{
"id": "ORD-1001",
"customer": "Amit Sharma",
"email": "amit@example.com",
"amount": 4999,
"status": "completed",
"date": "2025-02-01"
},
{
"id": "ORD-1002",
"customer": "Neha Verma",
"email": "neha@example.com",
"amount": 1999,
"status": "pending",
"date": "2025-02-02"
},
{
"id": "ORD-1003",
"customer": "Rahul Mehta",
"email": "rahul@example.com",
"amount": 2999,
"status": "failed",
"date": "2025-02-02"
},
{
"id": "ORD-1004",
"customer": "Priya Singh",
"email": "priya@example.com",
"amount": 9999,
"status": "completed",
"date": "2025-02-03"
}
],
"usersTable": [
{
"id": "USR-001",
"name": "Amit Sharma",
"email": "amit@example.com",
"role": "Admin",
"status": "active",
"lastLogin": "2025-02-07"
},
{
"id": "USR-002",
"name": "Neha Verma",
"email": "neha@example.com",
"role": "User",
"status": "inactive",
"lastLogin": "2025-01-29"
},
{
"id": "USR-003",
"name": "Rahul Mehta",
"email": "rahul@example.com",
"role": "Manager",
"status": "active",
"lastLogin": "2025-02-06"
}
],
"notifications": [
{
"id": 1,
"type": "warning",
"message": "Server CPU usage is above 80%"
},
{
"id": 2,
"type": "success",
"message": "New user registered successfully"
},
{
"id": 3,
"type": "error",
"message": "Payment gateway timeout detected"
}
]
}
We are going to follow this folder structure for making our life easier
src/
│
├── components/
│ ├── ui/
│ ├── layout/
│
├── pages/
│ └── Dashboard.jsx
│
├── data/
│ └── dashboardData.json
│
├── hooks/
│
├── lib/
│
├── App.jsx
├── main.jsx
└── index.css
src/pages/Dashboard.jsx
import data from "../data/dashboardData.json";
export default function Dashboard() {
return (
<div className="p-6">
<h1 className="text-2xl font-bold text-slate-800">
Dashboard
</h1>
<pre className="mt-6 bg-slate-900 text-green-400 p-4 rounded-lg overflow-auto">
{JSON.stringify(data.stats, null, 2)}
</pre>
</div>
);
}
Import the Dashboard in App.js file
import Dashboard from "./pages/Dashboard";
export default function App() {
return (
<div className="min-h-screen bg-slate-100">
<Dashboard />
</div>
);
}
run your vite code and see if you can see the stats data on your browser then congratulations you have seen your data stats info now let's start our actual Dashboard implementation.
Stat Cards
Now let's create a Card for showing some Data to our user
src/components/ui/StatCard.jsx
export default function StatCard({ title, value, subtitle, trend }) {
const isPositive = trend >= 0;
return (
<div className="rounded-xl bg-white p-6 shadow-sm border border-slate-200">
<p className="text-sm font-medium text-slate-500">
{title}
</p>
<h2 className="mt-2 text-3xl font-bold text-slate-900">
{value}
</h2>
{subtitle && (
<p className="mt-1 text-sm text-slate-500">
{subtitle}
</p>
)}
{trend !== undefined && (
<p
className={`mt-4 text-sm font-medium ${
isPositive ? "text-emerald-600" : "text-rose-600"
}`}
>
{isPositive ? "▲" : "▼"} {Math.abs(trend)}%
</p>
)}
</div>
);
}
let's import this StatCard and use in our project
src/pages/Dashboard.jsx
import data from "../data/dashboardData.json";
import StatCard from "../components/ui/StatCard";
export default function Dashboard() {
const { stats } = data;
return (
<div className="p-6 space-y-6">
<h1 className="text-2xl font-bold text-slate-800">
Dashboard
</h1>
{/* Stat Cards */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
<StatCard
title="Total Users"
value={stats.totalUsers.toLocaleString()}
trend={stats.growth.users}
/>
<StatCard
title="Active Users"
value={stats.activeUsers.toLocaleString()}
subtitle="Currently online"
/>
<StatCard
title="Monthly Revenue"
value={`₹${stats.monthlyRevenue.toLocaleString()}`}
trend={stats.growth.revenue}
/>
<StatCard
title="Conversion Rate"
value={`${stats.conversionRate}%`}
trend={stats.growth.orders}
/>
</div>
</div>
);
}
Sidebar + Header Layout
See If you have seen Dashboard then you must seen those Sidebar and Header in almost every Dashboard so let's create one.
src/components/layout/SideBar.jsx
export default function Sidebar() {
return (
<aside className="w-64 bg-slate-900 text-slate-100 flex flex-col">
<div className="px-6 py-4 text-xl font-bold border-b border-slate-800">
MyDashboard
</div>
<nav className="flex-1 px-4 py-6 space-y-2">
<button className="w-full text-left px-4 py-2 rounded-lg bg-slate-800">
Dashboard
</button>
<button className="w-full text-left px-4 py-2 rounded-lg hover:bg-slate-800">
Users
</button>
<button className="w-full text-left px-4 py-2 rounded-lg hover:bg-slate-800">
Orders
</button>
<button className="w-full text-left px-4 py-2 rounded-lg hover:bg-slate-800">
Settings
</button>
</nav>
</aside>
);
}
Header
src/components/layout/Header.jsx
export default function Header() {
return (
<header className="h-16 bg-white border-b border-slate-200 flex items-center justify-between px-6">
<h2 className="text-lg font-semibold text-slate-800">
Dashboard Overview
</h2>
<div className="flex items-center gap-4">
<span className="text-sm text-slate-600">
Hello, Admin
</span>
<div className="h-8 w-8 rounded-full bg-slate-300" />
</div>
</header>
);
}
Now wrap those around Dashboard
src/components/layout/DashboardLayout.jsx
import Sidebar from "./Sidebar";
import Header from "./Header";
export default function DashboardLayout({ children }) {
return (
<div className="min-h-screen flex bg-slate-100">
<Sidebar />
<div className="flex-1 flex flex-col">
<Header />
<main className="flex-1 p-6 overflow-y-auto">
{children}
</main>
</div>
</div>
);
}
Wrap Dashboard page with Layout
src/pages/Dashboard.jsx
import data from "../data/dashboardData.json";
import StatCard from "../components/ui/StatCard";
import DashboardLayout from "../components/layout/DashboardLayout";
export default function Dashboard() {
const { stats } = data;
return (
<DashboardLayout>
<div className="space-y-6">
{/* Stat Cards */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
<StatCard
title="Total Users"
value={stats.totalUsers.toLocaleString()}
trend={stats.growth.users}
/>
<StatCard
title="Active Users"
value={stats.activeUsers.toLocaleString()}
subtitle="Currently online"
/>
<StatCard
title="Monthly Revenue"
value={`₹${stats.monthlyRevenue.toLocaleString()}`}
trend={stats.growth.revenue}
/>
<StatCard
title="Conversion Rate"
value={`${stats.conversionRate}%`}
trend={stats.growth.orders}
/>
</div>
</div>
</DashboardLayout>
);
}
Let's Add Charts using Recharts
npm install recharts
create Two file
components/
└── charts/
├── RevenueLineChart.jsx
└── RevenuePieChart.jsx
src/components/charts/RevenueLineChart.jsx
import {
LineChart,
Line,
XAxis,
YAxis,
Tooltip,
ResponsiveContainer,
CartesianGrid
} from "recharts";
export default function RevenueLineChart({ data }) {
return (
<div className="bg-white p-6 rounded-xl border border-slate-200 shadow-sm">
<h3 className="text-lg font-semibold text-slate-800 mb-4">
Revenue Over Time
</h3>
<div className="h-72">
<ResponsiveContainer width="100%" height="100%">
<LineChart data={data}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="month" />
<YAxis />
<Tooltip />
<Line
type="monotone"
dataKey="revenue"
strokeWidth={3}
dot={false}
/>
</LineChart>
</ResponsiveContainer>
</div>
</div>
);
}
src/components/charts/RevenuePieChart.jsx
import {
PieChart,
Pie,
Tooltip,
ResponsiveContainer
} from "recharts";
export default function RevenuePieChart({ data }) {
return (
<div className="bg-white p-6 rounded-xl border border-slate-200 shadow-sm">
<h3 className="text-lg font-semibold text-slate-800 mb-4">
Revenue Distribution
</h3>
<div className="h-72">
<ResponsiveContainer width="100%" height="100%">
<PieChart>
<Pie
data={data}
dataKey="value"
nameKey="category"
outerRadius={100}
label
/>
<Tooltip />
</PieChart>
</ResponsiveContainer>
</div>
</div>
);
}
Use charts in Dashboard Page
src/pages/Dashboard.jsx
import data from "../data/dashboardData.json";
import StatCard from "../components/ui/StatCard";
import DashboardLayout from "../components/layout/DashboardLayout";
import RevenueLineChart from "../components/charts/RevenueLineChart";
import RevenuePieChart from "../components/charts/RevenuePieChart";
export default function Dashboard() {
const { stats, revenueOverTime, revenueByCategory } = data;
return (
<DashboardLayout>
<div className="space-y-6">
{/* Stat Cards */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
<StatCard
title="Total Users"
value={stats.totalUsers.toLocaleString()}
trend={stats.growth.users}
/>
<StatCard
title="Active Users"
value={stats.activeUsers.toLocaleString()}
subtitle="Currently online"
/>
<StatCard
title="Monthly Revenue"
value={`₹${stats.monthlyRevenue.toLocaleString()}`}
trend={stats.growth.revenue}
/>
<StatCard
title="Conversion Rate"
value={`${stats.conversionRate}%`}
trend={stats.growth.orders}
/>
</div>
{/* Charts */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div className="lg:col-span-2">
<RevenueLineChart data={revenueOverTime} />
</div>
<RevenuePieChart data={revenueByCategory} />
</div>
</div>
</DashboardLayout>
);
}
Now you can see two beautiful charts one Line chart and second Pie chart both use in Dashboard.
table-with-tanStack-table
Now let's implement Table with the help of Tanstack Table
npm install @tanstack/react-table
create a file OrderTable.jsx inside table folder
components/
└── table/
└── OrdersTable.jsx
src/components/table/OrdersTable.jsx
import {
flexRender,
getCoreRowModel,
useReactTable
} from "@tanstack/react-table";
export default function OrdersTable({ data, columns }) {
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel()
});
return (
<div className="bg-white rounded-xl border border-slate-200 shadow-sm overflow-hidden">
<div className="p-6 border-b border-slate-200">
<h3 className="text-lg font-semibold text-slate-800">
Recent Orders
</h3>
</div>
<table className="w-full text-sm">
<thead className="bg-slate-50 border-b border-slate-200">
{table.getHeaderGroups().map(headerGroup => (
<tr key={headerGroup.id}>
{headerGroup.headers.map(header => (
<th
key={header.id}
className="px-6 py-3 text-left font-medium text-slate-600"
>
{flexRender(
header.column.columnDef.header,
header.getContext()
)}
</th>
))}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.map(row => (
<tr
key={row.id}
className="border-b border-slate-100 hover:bg-slate-50"
>
{row.getVisibleCells().map(cell => (
<td key={cell.id} className="px-6 py-4 text-slate-700">
{flexRender(
cell.column.columnDef.cell,
cell.getContext()
)}
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
);
}
create ordercolumns
src/components/table/OrderColumns.jsx
this will help in send the columns data inside table
export const orderColumns = [
{
header: "Order ID",
accessorKey: "id"
},
{
header: "Customer",
accessorKey: "customer"
},
{
header: "Email",
accessorKey: "email"
},
{
header: "Amount",
accessorKey: "amount",
cell: info => `₹${info.getValue().toLocaleString()}`
},
{
header: "Status",
accessorKey: "status",
cell: info => {
const status = info.getValue();
const styles = {
completed: "bg-emerald-100 text-emerald-700",
pending: "bg-amber-100 text-amber-700",
failed: "bg-rose-100 text-rose-700"
};
return (
<span
className={`px-3 py-1 rounded-full text-xs font-medium ${styles[status]}`}
>
{status}
</span>
);
}
},
{
header: "Date",
accessorKey: "date"
}
];
finally impelment in Dashboard.jsx
import data from "../data/dashboardData.json";
import StatCard from "../components/ui/StatCard";
import DashboardLayout from "../components/layout/DashboardLayout";
import RevenueLineChart from "../components/charts/RevenueLineChart";
import RevenuePieChart from "../components/charts/RevenuePieChart";
import OrdersTable from "../components/table/OrdersTable";
import { orderColumns } from "../components/table/orderColumns";
export default function Dashboard() {
const {
stats,
revenueOverTime,
revenueByCategory,
recentOrders
} = data;
return (
<DashboardLayout>
<div className="space-y-6">
{/* Stat Cards */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
<StatCard title="Total Users" value={stats.totalUsers.toLocaleString()} trend={stats.growth.users} />
<StatCard title="Active Users" value={stats.activeUsers.toLocaleString()} subtitle="Currently online" />
<StatCard title="Monthly Revenue" value={`₹${stats.monthlyRevenue.toLocaleString()}`} trend={stats.growth.revenue} />
<StatCard title="Conversion Rate" value={`${stats.conversionRate}%`} trend={stats.growth.orders} />
</div>
{/* Charts */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div className="lg:col-span-2">
<RevenueLineChart data={revenueOverTime} />
</div>
<RevenuePieChart data={revenueByCategory} />
</div>
{/* Orders Table */}
<OrdersTable
data={recentOrders}
columns={orderColumns}
/>
</div>
</DashboardLayout>
);
}
so finally you implement Table also in your Dashboard.
If you can manage to make this till here then congratulation you are serious for your Journey 🎉
Top comments (0)