← TemplatesDashboard

SaaS Dashboard

A comprehensive admin dashboard for SaaS applications with analytics, user management, activity tracking, and revenue metrics. Built for scale.

Analytics ChartsUser ManagementActivity FeedRevenue TrackingCollapsible Sidebar

Overview

Built for Modern SaaS

This dashboard template provides a comprehensive admin interface for SaaS applications. Track revenue, manage users, monitor activity, and gain insights with beautiful visualizations and intuitive navigation.

📊

Real-time Analytics

Interactive charts and metrics with live data updates

👥

User Management

Customer table with filtering, status badges, and actions

📈

Revenue Tracking

Monthly revenue charts with comparison indicators

🔔

Activity Feed

Real-time notifications and user activity timeline

Live Demo

Dashboard

Welcome back, John. Here's what's happening.

Total Revenue
$54,239
+12.5%vs last month
Active Users
2,847
+8.2%vs last month
Conversion Rate
3.24%
-0.4%vs last month
Avg. Session
4m 32s
+15.3%vs last month

Revenue Overview

Revenue
$50k$40k$30k$20k$10k$0
Jan 2024
$15k+12%
Feb 2024
$20k+33%
Mar 2024
$17.5k-12%
Apr 2024
$30k+71%
May 2024
$25k-17%
Jun 2024
$27.5k+10%
Jul 2024
$35k+27%
Aug 2024
$28.75k-18%
Sep 2024
$32.5k+13%
Oct 2024
$40k+23%
Nov 2024
$31.25k-22%
Dec 2024
$36.25k+16%
JanFebMarAprMayJunJulAugSepOctNovDec

Recent Activity

Sarah A. upgraded to Pro plan

2 min ago

New user signed up for trial

15 min ago

Michael C. submitted support ticket

1 hour ago

Emily J. completed onboarding

2 hours ago

Recent Customers

CustomerPlanStatusActions
SA

Sarah Anderson

sarah@example.com

Proactive
MC

Michael Chen

michael@example.com

Enterpriseactive
EJ

Emily Johnson

emily@example.com

Starterpending
DK

David Kim

david@example.com

Proactive
LW

Lisa Wang

lisa@example.com

Starterinactive

Implementation Guide

1

Set Up Project Structure

Create the dashboard layout with sidebar and main content area.

step-1.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Recommended folder structure src/ app/ dashboard/ layout.tsx # Dashboard layout with sidebar page.tsx # Main dashboard analytics/page.tsx customers/page.tsx settings/page.tsx components/ dashboard/ Sidebar.tsx Header.tsx StatsCard.tsx ActivityFeed.tsx charts/ RevenueChart.tsx lib/ dashboard-context.tsx
2

Create Dashboard Layout

Build the base layout with collapsible sidebar and header.

step-2.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
"use client"; import { useState } from "react"; import { Sidebar } from "@/components/dashboard/Sidebar"; import { Header } from "@/components/dashboard/Header"; export default function DashboardLayout({ children }: { children: React.ReactNode }) { const [sidebarOpen, setSidebarOpen] = useState(true); return ( <div className="min-h-screen bg-slate-50 dark:bg-slate-950 flex"> <Sidebar isOpen={sidebarOpen} onToggle={() => setSidebarOpen(!sidebarOpen)} /> <div className="flex-1 flex flex-col"> <Header onMenuClick={() => setSidebarOpen(!sidebarOpen)} /> <main className="flex-1 p-6"> {children} </main> </div> </div> ); }
3

Build Stats Cards Component

Create reusable stat cards with icons and change indicators.

step-3.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
interface StatCardProps { label: string; value: string; change: string; trend: "up" | "down"; icon: React.ReactNode; } function StatCard({ label, value, change, trend, icon }: StatCardProps) { return ( <div className="p-6 bg-white dark:bg-slate-900 rounded-2xl border border-slate-200 dark:border-slate-800"> <div className="flex items-center justify-between mb-3"> <span className="text-sm text-slate-500">{label}</span> <div className="p-2 bg-slate-100 dark:bg-slate-800 rounded-lg"> {icon} </div> </div> <div className="flex items-end justify-between"> <span className="text-3xl font-bold text-slate-900 dark:text-white"> {value} </span> <span className={`text-sm font-medium px-2 py-0.5 rounded-full ${ trend === "up" ? "bg-emerald-100 text-emerald-700" : "bg-red-100 text-red-700" }`}> {change} </span> </div> </div> ); }
4

Implement Revenue Chart

Create an interactive bar chart for revenue visualization.

step-4.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
function RevenueChart({ data }: { data: number[] }) { return ( <div className="p-6 bg-white dark:bg-slate-900 rounded-2xl border"> <div className="flex items-center justify-between mb-6"> <h3 className="text-lg font-semibold">Revenue Overview</h3> <select className="px-3 py-1.5 text-sm border rounded-lg"> <option>Last 12 months</option> <option>Last 6 months</option> </select> </div> <div className="h-64 flex items-end gap-3"> {data.map((value, i) => ( <div key={i} className="flex-1"> <div className="bg-purple-100 rounded-t-lg relative overflow-hidden" style={{ height: `${value}%` }} > <div className="absolute bottom-0 inset-x-0 bg-gradient-to-t from-purple-600 to-purple-400 rounded-t-lg" style={{ height: "60%" }} /> </div> </div> ))} </div> <div className="grid grid-cols-12 mt-3 text-xs text-slate-500"> {["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"] .map(m => <span key={m} className="text-center">{m}</span>)} </div> </div> ); }

Full Source Code

saas-dashboard.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
"use client"; import { useState } from "react"; interface StatItem { label: string; value: string; change: string; up: boolean; icon: string; } interface User { name: string; email: string; plan: string; status: string; avatar: string; } interface Activity { user: string; action: string; time: string; type: string; } export default function SaaSDashboard() { const [sidebarOpen, setSidebarOpen] = useState(true); const stats: StatItem[] = [ { label: "Total Revenue", value: "$54,239", change: "+12.5%", up: true, icon: "dollar" }, { label: "Active Users", value: "2,847", change: "+8.2%", up: true, icon: "users" }, { label: "Conversion Rate", value: "3.24%", change: "-0.4%", up: false, icon: "chart" }, { label: "Avg. Session", value: "4m 32s", change: "+15.3%", up: true, icon: "clock" }, ]; const recentUsers: User[] = [ { name: "Sarah Anderson", email: "sarah@example.com", plan: "Pro", status: "active", avatar: "SA" }, { name: "Michael Chen", email: "michael@example.com", plan: "Enterprise", status: "active", avatar: "MC" }, { name: "Emily Johnson", email: "emily@example.com", plan: "Starter", status: "pending", avatar: "EJ" }, ]; const activities: Activity[] = [ { user: "Sarah A.", action: "upgraded to Pro plan", time: "2 min ago", type: "upgrade" }, { user: "New user", action: "signed up for trial", time: "15 min ago", type: "signup" }, { user: "Michael C.", action: "submitted support ticket", time: "1 hour ago", type: "support" }, ]; return ( <div className="min-h-screen bg-slate-50 dark:bg-slate-950 flex"> {/* Collapsible Sidebar */} <aside className={`${sidebarOpen ? "w-64" : "w-0"} bg-white dark:bg-slate-900 border-r transition-all`}> <div className="w-64 h-full flex flex-col"> {/* Logo */} <div className="flex items-center gap-3 px-6 h-16 border-b"> <div className="w-8 h-8 bg-gradient-to-br from-purple-500 to-indigo-600 rounded-lg flex items-center justify-center text-white font-bold"> S </div> <span className="text-lg font-bold">SaaSify</span> </div> {/* Navigation */} <nav className="p-4 space-y-1 flex-1"> {["Dashboard", "Analytics", "Customers", "Products", "Orders", "Messages", "Settings"].map((item) => ( <button key={item} className="w-full flex items-center gap-3 px-4 py-2.5 rounded-xl text-sm font-medium hover:bg-slate-100" > {item} </button> ))} </nav> {/* User Profile */} <div className="p-4 border-t"> <div className="flex items-center gap-3"> <div className="w-10 h-10 rounded-full bg-gradient-to-br from-purple-500 to-pink-500 flex items-center justify-center text-white font-semibold"> JD </div> <div> <p className="text-sm font-medium">John Doe</p> <p className="text-xs text-slate-500">john@saasify.com</p> </div> </div> </div> </div> </aside> {/* Main Content */} <div className="flex-1 flex flex-col"> {/* Header */} <header className="sticky top-0 z-30 h-16 bg-white/80 backdrop-blur-xl border-b"> <div className="flex items-center justify-between h-full px-6"> <button onClick={() => setSidebarOpen(!sidebarOpen)} className="p-2 hover:bg-slate-100 rounded-lg"> {/* Menu Icon */} </button> <div className="flex items-center gap-3"> {/* Search, Notifications, User Avatar */} </div> </div> </header> {/* Dashboard Content */} <main className="flex-1 p-6 space-y-6"> {/* Stats Grid */} <div className="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-5"> {stats.map((stat) => ( <div key={stat.label} className="p-6 bg-white rounded-2xl border shadow-sm"> <div className="flex items-center justify-between mb-3"> <span className="text-sm text-slate-500">{stat.label}</span> {/* Icon */} </div> <div className="flex items-end justify-between"> <span className="text-xl sm:text-2xl font-bold">{stat.value}</span> <span className={`text-sm px-2 py-0.5 rounded-full ${ stat.up ? "bg-emerald-100 text-emerald-700" : "bg-red-100 text-red-700" }`}> {stat.change} </span> </div> </div> ))} </div> {/* Charts and Activity */} <div className="grid grid-cols-1 lg:grid-cols-3 gap-6"> {/* Revenue Chart - Edge to Edge with Data Points */} <div className="lg:col-span-2 bg-white rounded-2xl border overflow-hidden flex flex-col"> <div className="p-4 border-b flex items-center justify-between"> <h3 className="text-lg font-semibold">Revenue Overview</h3> <div className="flex items-center gap-4 text-xs text-slate-500"> <span className="flex items-center gap-1.5"> <span className="w-2 h-2 rounded-full bg-purple-500"></span>Revenue </span> </div> </div> <div className="flex-1 min-h-[220px] relative"> {/* Y-axis labels */} <div className="absolute left-3 top-0 bottom-8 flex flex-col justify-between text-xs text-slate-400 z-10"> <span>$50k</span><span>$40k</span><span>$30k</span><span>$20k</span><span>$10k</span><span>$0</span> </div> {/* Grid lines - edge to edge */} <div className="absolute inset-0 bottom-8 flex flex-col justify-between pointer-events-none"> {[0, 1, 2, 3, 4, 5].map((i) => ( <div key={i} className="border-b border-slate-100" /> ))} </div> {/* Line chart SVG - edge to edge */} <svg className="absolute inset-0 w-full" style={{ height: 'calc(100% - 32px)' }} viewBox="0 0 400 200" preserveAspectRatio="none"> <defs> <linearGradient id="lineGradient" x1="0%" y1="0%" x2="0%" y2="100%"> <stop offset="0%" stopColor="rgb(147, 51, 234)" stopOpacity="0.3" /> <stop offset="100%" stopColor="rgb(147, 51, 234)" stopOpacity="0" /> </linearGradient> </defs> <path d="M0,140 L33,120 L66,130 L100,80 L133,100 L166,90 L200,60 L233,85 L266,70 L300,40 L333,75 L366,55 L400,45 L400,200 L0,200 Z" fill="url(#lineGradient)" /> <path d="M0,140 L33,120 L66,130 L100,80 L133,100 L166,90 L200,60 L233,85 L266,70 L300,40 L333,75 L366,55 L400,45" fill="none" stroke="rgb(147, 51, 234)" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" vectorEffect="non-scaling-stroke" /> </svg> {/* Data points overlay with hover tooltips */} <div className="absolute inset-0" style={{ height: 'calc(100% - 32px)' }}> {[ { x: 0, y: 70, month: "Jan", value: 15, change: "+12%" }, { x: 8.25, y: 60, month: "Feb", value: 20, change: "+33%" }, { x: 16.5, y: 65, month: "Mar", value: 17.5, change: "-12%" }, { x: 25, y: 40, month: "Apr", value: 30, change: "+71%" }, { x: 33.25, y: 50, month: "May", value: 25, change: "-17%" }, { x: 41.5, y: 45, month: "Jun", value: 27.5, change: "+10%" }, { x: 50, y: 30, month: "Jul", value: 35, change: "+27%" }, { x: 58.25, y: 42.5, month: "Aug", value: 28.75, change: "-18%" }, { x: 66.5, y: 35, month: "Sep", value: 32.5, change: "+13%" }, { x: 75, y: 20, month: "Oct", value: 40, change: "+23%" }, { x: 83.25, y: 37.5, month: "Nov", value: 31.25, change: "-22%" }, { x: 91.5, y: 27.5, month: "Dec", value: 36.25, change: "+16%" } ].map((point, i) => ( <div key={i} className="absolute group z-20 hover:z-50" style={{ left: \`\${point.x}%\`, top: \`\${point.y}%\` }}> <div className="w-3 h-3 bg-white border-2 border-purple-500 rounded-full transform -translate-x-1/2 -translate-y-1/2 group-hover:scale-150 transition-transform cursor-pointer" /> {/* Tooltip */} <div className="absolute bottom-full left-1/2 -translate-x-1/2 mb-2 opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none z-50"> <div className="bg-slate-900 text-white text-xs rounded-lg px-3 py-2 whitespace-nowrap shadow-lg"> <div className="font-semibold">{point.month} 2024</div> <div className="flex items-center gap-2 mt-1"> <span className="text-purple-400 font-bold">${point.value}k</span> <span className={point.change.startsWith("+") ? "text-emerald-400" : "text-red-400"}>{point.change}</span> </div> </div> <div className="absolute top-full left-1/2 -translate-x-1/2 border-4 border-transparent border-t-slate-900" /> </div> </div> ))} </div> {/* X-axis labels */} <div className="absolute bottom-0 left-0 right-0 h-8 flex justify-between items-center text-xs text-slate-400"> {["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"].map((m) => ( <span key={m} className="text-center" style={{ width: '8.33%' }}>{m}</span> ))} </div> </div> </div> {/* Activity Feed */} <div className="p-6 bg-white rounded-2xl border"> <h3 className="text-lg font-semibold mb-4">Recent Activity</h3> <div className="space-y-4"> {activities.map((activity, i) => ( <div key={i} className="flex items-start gap-3"> {/* Activity Icon */} <div> <p className="text-sm"> <span className="font-medium">{activity.user}</span> {activity.action} </p> <p className="text-xs text-slate-500">{activity.time}</p> </div> </div> ))} </div> </div> </div> {/* Users Table */} <div className="bg-white rounded-2xl border overflow-hidden"> <div className="flex items-center justify-between p-6 border-b"> <h3 className="text-lg font-semibold">Recent Customers</h3> <button className="text-sm text-purple-600 font-medium">View all</button> </div> <table className="w-full"> <thead> <tr className="border-b bg-slate-50"> <th className="px-6 py-4 text-left text-xs font-semibold text-slate-500 uppercase">Customer</th> <th className="px-6 py-4 text-left text-xs font-semibold text-slate-500 uppercase">Plan</th> <th className="px-6 py-4 text-left text-xs font-semibold text-slate-500 uppercase">Status</th> <th className="px-6 py-4 text-right text-xs font-semibold text-slate-500 uppercase">Actions</th> </tr> </thead> <tbody> {recentUsers.map((user) => ( <tr key={user.email} className="border-b hover:bg-slate-50"> <td className="px-6 py-4"> <div className="flex items-center gap-3"> <div className="w-10 h-10 rounded-full bg-gradient-to-br from-purple-500 to-pink-500 flex items-center justify-center text-white font-semibold text-sm"> {user.avatar} </div> <div> <p className="font-medium">{user.name}</p> <p className="text-sm text-slate-500">{user.email}</p> </div> </div> </td> <td className="px-6 py-4"> <span className="px-2.5 py-1 text-xs font-medium rounded-full bg-purple-100 text-purple-700"> {user.plan} </span> </td> <td className="px-6 py-4"> <span className="px-2.5 py-1 text-xs font-medium rounded-full bg-emerald-100 text-emerald-700"> {user.status} </span> </td> <td className="px-6 py-4 text-right"> <button className="p-2 hover:bg-slate-100 rounded-lg"></button> </td> </tr> ))} </tbody> </table> </div> </main> </div> </div> ); }

Customization Guide

Brand Colors

Update the color scheme to match your brand identity.

customization.tsx
// Replace purple with your brand color
// In tailwind.config.ts:
colors: {
  brand: {
    50: '#faf5ff',
    500: '#a855f7',
    600: '#9333ea',
    700: '#7e22ce',
  }
}

// Then update classes:
// bg-purple-600 → bg-brand-600
// text-purple-500 → text-brand-500

Navigation Items

Customize sidebar navigation for your app's needs.

customization.tsx
const navItems = [
  { label: "Dashboard", icon: HomeIcon, href: "/dashboard" },
  { label: "Analytics", icon: ChartIcon, href: "/analytics" },
  { label: "Customers", icon: UsersIcon, href: "/customers", badge: 3 },
  { label: "Products", icon: BoxIcon, href: "/products" },
  { label: "Billing", icon: CreditCardIcon, href: "/billing" },
  { label: "Settings", icon: SettingsIcon, href: "/settings" },
];

// Add dividers between sections
const navSections = [
  { title: "Main", items: navItems.slice(0, 4) },
  { title: "Account", items: navItems.slice(4) },
];

Stats Configuration

Configure which metrics to display on the dashboard.

customization.tsx
const dashboardStats = [
  {
    label: "Total Revenue",
    value: formatCurrency(revenue),
    change: calculateChange(revenue, lastRevenue),
    icon: <DollarIcon />,
    color: "purple",
  },
  {
    label: "Active Users",
    value: formatNumber(users),
    change: calculateChange(users, lastUsers),
    icon: <UsersIcon />,
    color: "cyan",
  },
  // Add more metrics as needed
];

Chart Integration

Replace simple charts with a charting library like Recharts.

customization.tsx
import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer } from 'recharts';

function RevenueChart({ data }) {
  return (
    <ResponsiveContainer width="100%" height={256}>
      <BarChart data={data}>
        <XAxis dataKey="month" />
        <YAxis />
        <Tooltip />
        <Bar
          dataKey="revenue"
          fill="#a855f7"
          radius={[4, 4, 0, 0]}
        />
      </BarChart>
    </ResponsiveContainer>
  );
}

Ready to Build Your Dashboard?

Copy this template, customize it to your brand, and start tracking your metrics. All the components you need are included.