Project: Build a Responsive Admin Dashboard UI
Step-by-step project guide. Learn how to build an advanced, responsive dark-themed admin dashboard interface using Grid, Flexbox, and custom scrollbars.
Introduction
In our previous projects, we built a portfolio using Flexbox and a product landing page using CSS Grid. In production web engineering, you will rarely use just one layout engine. Instead, you will combine them: using CSS Grid to structure the overall page layout and Flexbox to align content inside individual components.
In this third capstone project, you will build a Responsive Admin Dashboard UI. This dashboard features a persistent sidebar (desktop), a stats card matrix, a recent activity timeline, and a responsive data table. We will style it with a dark theme, using glassmorphic borders and custom scrollbars, making it a capstone project for your placement portfolio.
What You Will Learn
- Combining Grid and Flexbox in a single interface.
- Creating a persistent sidebar that collapses into a drawer on mobile.
- Building responsive stat grid containers.
- Styling custom scrollbars for data panels.
- Creating status badges using flex alignments.
Prerequisites
- Project: Build a SaaS Product Landing Page using CSS Grid
- Overflow Handling: Visible, Hidden, Scroll, and Custom Scrollbars
Step 1: The HTML5 Document Markup
Create a dashboard.html file to structure the sidebar, header, stats grid, data table, and analytics console:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin Dashboard Console</title>
<link rel="stylesheet" href="dashboard.css">
</head>
<body>
<!-- Main Grid Wrapper -->
<div class="dashboard-wrapper">
<!-- Sidebar Navigation -->
<aside class="sidebar">
<div class="logo">ConsoleDB</div>
<nav class="sidebar-nav">
<a href="#" class="active">📊 Overview</a>
<a href="#">📈 Analytics</a>
<a href="#">👥 Users</a>
<a href="#">⚙️ Settings</a>
</nav>
</aside>
<!-- Header Panel -->
<header class="header">
<div class="header-title">Overview Dashboard</div>
<div class="header-profile">
<span class="user-name">John Doe</span>
<div class="avatar">JD</div>
</div>
</header>
<!-- Main Content Area -->
<main class="main-content">
<!-- Stats Matrix (Row 1) -->
<section class="stats-grid">
<div class="stat-card">
<div class="stat-header">Total Revenue</div>
<div class="stat-value">$45,231</div>
<div class="stat-change positive">+12.5% from last month</div>
</div>
<div class="stat-card">
<div class="stat-header">Active Users</div>
<div class="stat-value">+2,350</div>
<div class="stat-change positive">+18.2% from last month</div>
</div>
<div class="stat-card">
<div class="stat-header">Server Latency</div>
<div class="stat-value">12ms</div>
<div class="stat-change negative">-2.4% from last hour</div>
</div>
</section>
<!-- Data Section (Row 2) -->
<section class="data-section">
<!-- Recent Orders Card -->
<div class="data-card scroll-container">
<h3>Recent Transactions</h3>
<table class="data-table">
<thead>
<tr>
<th>Invoice</th>
<th>Status</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
<tr>
<td>INV-001</td>
<td><span class="badge status-success">Success</span></td>
<td>$250.00</td>
</tr>
<tr>
<td>INV-002</td>
<td><span class="badge status-pending">Pending</span></td>
<td>$89.00</td>
</tr>
<tr>
<td>INV-003</td>
<td><span class="badge status-failed">Failed</span></td>
<td>$410.00</td>
</tr>
</tbody>
</table>
</div>
</section>
</main>
</div>
</body>
</html>
Step 2: The CSS Stylesheet (dashboard.css)
Create a dashboard.css file. We will use CSS Grid to structure the page template, and Flexbox to align the component details:
/* ==========================================================================
Design Tokens & Base Resets
========================================================================== */
:root {
--bg-app: #090d16;
--bg-panel: #111827;
--bg-card: #1f2937;
--border-subtle: rgba(255, 255, 255, 0.05);
--color-indigo: #6366f1;
--color-emerald: #10b981;
--color-rose: #f43f5e;
--color-amber: #f59e0b;
--text-white: #ffffff;
--text-gray: #9ca3af;
--font-sans: 'Inter', system-ui, sans-serif;
}
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background-color: var(--bg-app);
color: var(--text-white);
font-family: var(--font-sans);
overflow: hidden; /* Avoid page scrollbars; scroll inside main content instead */
height: 100vh;
}
/* ==========================================================================
Dashboard Grid Layout
========================================================================== */
.dashboard-wrapper {
display: grid;
/* Sidebar: 260px, Main Content: fills remaining space */
grid-template-columns: 260px 1fr;
/* Header: 70px, Main: fills remaining height */
grid-template-rows: 70px 1fr;
height: 100vh;
grid-template-areas:
"sidebar header"
"sidebar main";
}
.sidebar { grid-area: sidebar; }
.header { grid-area: header; }
.main-content { grid-area: main; }
/* ==========================================================================
Sidebar Panel (Flexbox Column)
========================================================================== */
.sidebar {
background-color: var(--bg-panel);
border-right: 1px solid var(--border-subtle);
display: flex;
flex-direction: column;
padding: 24px;
}
.logo {
font-size: 1.5rem;
font-weight: 800;
color: var(--color-indigo);
margin-bottom: 40px;
}
.sidebar-nav {
display: flex;
flex-direction: column;
gap: 8px;
}
.sidebar-nav a {
color: var(--text-gray);
text-decoration: none;
padding: 12px 16px;
border-radius: 8px;
font-weight: 500;
transition: all 0.2s;
}
.sidebar-nav a.active,
.sidebar-nav a:hover {
background-color: var(--bg-card);
color: var(--text-white);
}
/* ==========================================================================
Header Panel (Flexbox Row)
========================================================================== */
.header {
background-color: var(--bg-panel);
border-bottom: 1px solid var(--border-subtle);
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 32px;
}
.header-title {
font-size: 1.25rem;
font-weight: 700;
}
.header-profile {
display: flex;
align-items: center;
gap: 12px;
}
.avatar {
width: 36px;
height: 36px;
border-radius: 50%;
background-color: var(--color-indigo);
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
font-size: 0.875rem;
}
/* ==========================================================================
Main Content Area
========================================================================== */
.main-content {
padding: 32px;
overflow-y: auto; /* Enable scrollbars on content area only */
}
/* Custom Scrollbar Styles for Content Area */
.main-content::-webkit-scrollbar {
width: 6px;
}
.main-content::-webkit-scrollbar-track {
background: transparent;
}
.main-content::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.1);
border-radius: 3px;
}
/* ==========================================================================
Stats Grid (CSS Grid auto-fit)
========================================================================== */
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 24px;
margin-bottom: 32px;
}
.stat-card {
background-color: var(--bg-panel);
border: 1px solid var(--border-subtle);
padding: 24px;
border-radius: 12px;
}
.stat-header {
font-size: 0.875rem;
color: var(--text-gray);
margin-bottom: 12px;
}
.stat-value {
font-size: 2rem;
font-weight: 800;
margin-bottom: 8px;
}
.stat-change {
font-size: 0.75rem;
font-weight: 500;
}
.stat-change.positive { color: var(--color-emerald); }
.stat-change.negative { color: var(--color-rose); }
/* ==========================================================================
Data Table Card
========================================================================== */
.data-card {
background-color: var(--bg-panel);
border: 1px solid var(--border-subtle);
padding: 24px;
border-radius: 12px;
}
.data-card h3 {
margin-bottom: 20px;
}
.data-table {
width: 100%;
border-collapse: collapse;
text-align: left;
}
.data-table th,
.data-table td {
padding: 16px;
border-bottom: 1px solid var(--border-subtle);
}
.data-table th {
color: var(--text-gray);
font-weight: 500;
}
/* Badges Alignment */
.badge {
display: inline-flex;
align-items: center;
padding: 4px 10px;
border-radius: 20px;
font-size: 0.75rem;
font-weight: 600;
}
.status-success { background-color: rgba(16, 185, 129, 0.1); color: var(--color-emerald); }
.status-pending { background-color: rgba(245, 158, 11, 0.1); color: var(--color-amber); }
.status-failed { background-color: rgba(244, 63, 94, 0.1); color: var(--color-rose); }
Responsive Restructuring (Mobile Breakpoints)
Add media queries at the bottom of dashboard.css to collapse the sidebar layout on mobile screens:
@media (max-width: 768px) {
/* Restructure layout to single column stack, removing sidebar from grid areas */
.dashboard-wrapper {
grid-template-columns: 1fr;
grid-template-rows: 70px 1fr;
grid-template-areas:
"header"
"main";
}
/* Hide the desktop sidebar */
.sidebar {
display: none;
}
.main-content {
padding: 20px;
}
/* Enable horizontal scroll on tables to prevent overflow layout breakages */
.scroll-container {
overflow-x: auto;
}
.data-table {
min-width: 500px;
}
}
Summary
This Responsive Admin Dashboard UI uses a multi-axis CSS Grid template wrapper to structure sidebar-header interfaces. Element statistics are laid out using auto-fit columns, transactions lists are nested within horizontal overflow tables, and profile cards are aligned responsively utilizing Flexbox rows.
Related Articles
Next Tutorial
Ready to prepare for frontend developer technical interviews? Let's check: CSS Placement Interview Questions.