DEV Community

Cover image for How i Create a dashboard
Navin Yadav
Navin Yadav

Posted on

How i Create a dashboard

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"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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"
  }
];
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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)