Skip to content

Solution: Admin Dashboard

ลองเล่น Admin Dashboard ที่สมบูรณ์แล้ว — ลองคลิก sidebar, ดู data table, และลองบนมือถือดู

dashboard Complete Demo INTERACTIVE
Admin
Total Users
1,234
Revenue
$45.6K
Active Now
89
Name Email Role Status
Somchai K.somchai@mail.comAdminActive
Nattaya P.nattaya@mail.comEditorActive
Prawit S.prawit@mail.comViewerInactive
Mayuree T.mayuree@mail.comEditorPending
Wichai R.wichai@mail.comAdminActive
  • Directoryadmin-dashboard/
    • index.html หน้า Dashboard หลัก พร้อม Sidebar, Table, Modal
    • style.css Tailwind CDN + custom animations
    • script.js JavaScript สำหรับ Sidebar toggle, Modal, Mobile menu
Show index.html
index.html
<!DOCTYPE html>
<html lang="th">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Admin Dashboard</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="style.css" />
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'Noto Sans Thai', 'system-ui', 'sans-serif'],
},
},
},
}
</script>
</head>
<body class="bg-gray-50 text-gray-900 font-sans">
<div class="flex min-h-screen">
<!-- ==================== SIDEBAR (Desktop) ==================== -->
<aside id="sidebar"
class="hidden lg:flex lg:flex-col lg:w-64 bg-gray-900 text-white
fixed inset-y-0 left-0 z-40">
<!-- Brand -->
<div class="flex items-center gap-3 px-6 h-16 border-b border-gray-800">
<div class="flex items-center justify-center w-8 h-8 bg-cyan-500 rounded-lg">
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6z
M14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6z
M4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2z
M14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z" />
</svg>
</div>
<span class="text-lg font-bold">AdminPanel</span>
</div>
<!-- Navigation -->
<nav class="flex flex-col gap-1 p-4 flex-1">
<a href="#" class="flex items-center gap-3 px-3 py-2.5 bg-gray-800 text-white rounded-lg text-sm font-medium">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-4 0h4" />
</svg>
Dashboard
</a>
<a href="#" class="flex items-center gap-3 px-3 py-2.5 text-gray-400 hover:bg-gray-800 hover:text-white rounded-lg text-sm transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197m13.5-9a2.25 2.25 0 11-4.5 0 2.25 2.25 0 014.5 0z" />
</svg>
Users
</a>
<a href="#" class="flex items-center gap-3 px-3 py-2.5 text-gray-400 hover:bg-gray-800 hover:text-white rounded-lg text-sm transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" />
</svg>
Products
</a>
<a href="#" class="flex items-center gap-3 px-3 py-2.5 text-gray-400 hover:bg-gray-800 hover:text-white rounded-lg text-sm transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
</svg>
Analytics
</a>
<a href="#" class="flex items-center gap-3 px-3 py-2.5 text-gray-400 hover:bg-gray-800 hover:text-white rounded-lg text-sm transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.066 2.573c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.573 1.066c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.066-2.573c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
Settings
</a>
</nav>
<!-- User Info -->
<div class="flex items-center gap-3 px-6 py-4 border-t border-gray-800">
<div class="flex items-center justify-center w-8 h-8 bg-cyan-600 rounded-full text-sm font-bold">
A
</div>
<div class="min-w-0 flex-1">
<p class="text-sm font-medium truncate">Admin User</p>
<p class="text-xs text-gray-400 truncate">admin@example.com</p>
</div>
</div>
</aside>
<!-- ==================== MOBILE SIDEBAR OVERLAY ==================== -->
<div id="mobile-overlay"
class="fixed inset-0 z-50 hidden lg:hidden">
<!-- Backdrop -->
<div class="fixed inset-0 bg-black/50 backdrop-blur-sm"
onclick="closeMobileSidebar()"></div>
<!-- Drawer -->
<aside class="fixed inset-y-0 left-0 w-72 bg-gray-900 text-white shadow-xl
transform transition-transform duration-300">
<div class="flex items-center justify-between px-6 h-16 border-b border-gray-800">
<div class="flex items-center gap-3">
<div class="flex items-center justify-center w-8 h-8 bg-cyan-500 rounded-lg">
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6z
M14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6z
M4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2z
M14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z" />
</svg>
</div>
<span class="text-lg font-bold">AdminPanel</span>
</div>
<button onclick="closeMobileSidebar()"
class="p-2 text-gray-400 hover:text-white rounded-lg transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<nav class="flex flex-col gap-1 p-4">
<a href="#" class="flex items-center gap-3 px-3 py-2.5 bg-gray-800 text-white rounded-lg text-sm font-medium">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-4 0h4" />
</svg>
Dashboard
</a>
<a href="#" class="flex items-center gap-3 px-3 py-2.5 text-gray-400 hover:bg-gray-800 hover:text-white rounded-lg text-sm transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197m13.5-9a2.25 2.25 0 11-4.5 0 2.25 2.25 0 014.5 0z" />
</svg>
Users
</a>
<a href="#" class="flex items-center gap-3 px-3 py-2.5 text-gray-400 hover:bg-gray-800 hover:text-white rounded-lg text-sm transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" />
</svg>
Products
</a>
<a href="#" class="flex items-center gap-3 px-3 py-2.5 text-gray-400 hover:bg-gray-800 hover:text-white rounded-lg text-sm transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.066 2.573c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.573 1.066c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.066-2.573c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
Settings
</a>
</nav>
</aside>
</div>
<!-- ==================== MAIN CONTENT ==================== -->
<div class="flex-1 lg:ml-64">
<!-- Top Header -->
<header class="sticky top-0 z-30 flex items-center justify-between h-16 px-4 sm:px-6 lg:px-8
bg-white/80 backdrop-blur-md border-b border-gray-200">
<!-- Mobile Menu Button -->
<button onclick="openMobileSidebar()"
class="lg:hidden p-2 -ml-2 text-gray-600 hover:text-gray-900 hover:bg-gray-100 rounded-lg transition-colors">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 6h16M4 12h16M4 18h16" />
</svg>
</button>
<!-- Page Title -->
<h1 class="text-lg font-bold text-gray-900 lg:text-xl">Dashboard</h1>
<!-- Right Side: Search + Profile -->
<div class="flex items-center gap-3">
<!-- Search (hidden on small mobile) -->
<div class="hidden sm:flex items-center gap-2 px-3 py-1.5 bg-gray-100 rounded-lg">
<svg class="w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
<input type="text" placeholder="Search..."
class="bg-transparent border-none outline-none text-sm text-gray-600 w-40 lg:w-56" />
</div>
<!-- Notification Bell -->
<button class="relative p-2 text-gray-500 hover:text-gray-700 hover:bg-gray-100 rounded-lg transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" />
</svg>
<span class="absolute top-1.5 right-1.5 w-2 h-2 bg-red-500 rounded-full"></span>
</button>
<!-- Avatar -->
<div class="flex items-center justify-center w-8 h-8 bg-cyan-600 rounded-full text-white text-sm font-bold cursor-pointer">
A
</div>
</div>
</header>
<!-- Dashboard Content -->
<main class="p-4 sm:p-6 lg:p-8">
<!-- Stats Cards -->
<div class="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-4 mb-8">
<!-- Total Users -->
<div class="flex items-center gap-4 p-5 bg-white border border-gray-200 rounded-xl
hover:shadow-md transition-shadow">
<div class="flex items-center justify-center w-12 h-12 bg-cyan-50 text-cyan-600 rounded-xl">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197m13.5-9a2.25 2.25 0 11-4.5 0 2.25 2.25 0 014.5 0z" />
</svg>
</div>
<div>
<p class="text-2xl font-bold text-gray-900">2,451</p>
<p class="text-sm text-gray-500">Total Users</p>
</div>
</div>
<!-- Revenue -->
<div class="flex items-center gap-4 p-5 bg-white border border-gray-200 rounded-xl
hover:shadow-md transition-shadow">
<div class="flex items-center justify-center w-12 h-12 bg-green-50 text-green-600 rounded-xl">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
<div>
<p class="text-2xl font-bold text-gray-900">$45,231</p>
<p class="text-sm text-gray-500">Revenue</p>
</div>
</div>
<!-- Orders -->
<div class="flex items-center gap-4 p-5 bg-white border border-gray-200 rounded-xl
hover:shadow-md transition-shadow">
<div class="flex items-center justify-center w-12 h-12 bg-purple-50 text-purple-600 rounded-xl">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z" />
</svg>
</div>
<div>
<p class="text-2xl font-bold text-gray-900">1,327</p>
<p class="text-sm text-gray-500">Orders</p>
</div>
</div>
<!-- Active Now -->
<div class="flex items-center gap-4 p-5 bg-white border border-gray-200 rounded-xl
hover:shadow-md transition-shadow">
<div class="flex items-center justify-center w-12 h-12 bg-amber-50 text-amber-600 rounded-xl">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M13 10V3L4 14h7v7l9-11h-7z" />
</svg>
</div>
<div>
<p class="text-2xl font-bold text-gray-900">573</p>
<p class="text-sm text-gray-500">Active Now</p>
</div>
</div>
</div>
<!-- Users Table Section -->
<div class="bg-white border border-gray-200 rounded-xl overflow-hidden">
<!-- Table Header -->
<div class="flex items-center justify-between px-6 py-4 border-b border-gray-200">
<div>
<h2 class="text-lg font-bold text-gray-900">Users</h2>
<p class="text-sm text-gray-500">Manage your team members</p>
</div>
<button onclick="openModal()"
class="inline-flex items-center gap-2 px-4 py-2 bg-cyan-600 hover:bg-cyan-700
text-white text-sm font-medium rounded-lg transition-colors">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 4v16m8-8H4" />
</svg>
Add User
</button>
</div>
<!-- Desktop Table (hidden on mobile) -->
<div class="hidden md:block overflow-x-auto">
<table class="w-full">
<thead>
<tr class="border-b border-gray-100 bg-gray-50/50">
<th class="px-6 py-3 text-left text-xs font-semibold text-gray-500 uppercase tracking-wider">Name</th>
<th class="px-6 py-3 text-left text-xs font-semibold text-gray-500 uppercase tracking-wider">Email</th>
<th class="px-6 py-3 text-left text-xs font-semibold text-gray-500 uppercase tracking-wider">Role</th>
<th class="px-6 py-3 text-left text-xs font-semibold text-gray-500 uppercase tracking-wider">Status</th>
<th class="px-6 py-3 text-right text-xs font-semibold text-gray-500 uppercase tracking-wider">Actions</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-100">
<tr class="hover:bg-gray-50 transition-colors">
<td class="px-6 py-4">
<div class="flex items-center gap-3">
<div class="flex items-center justify-center w-9 h-9 bg-blue-100 text-blue-700 rounded-full text-sm font-bold">S</div>
<span class="text-sm font-medium text-gray-900">Somchai K.</span>
</div>
</td>
<td class="px-6 py-4 text-sm text-gray-500">somchai@example.com</td>
<td class="px-6 py-4 text-sm text-gray-500">Admin</td>
<td class="px-6 py-4">
<span class="inline-flex items-center gap-1 px-2.5 py-1 text-xs font-medium bg-green-50 text-green-700 rounded-full">
<span class="w-1.5 h-1.5 bg-green-500 rounded-full"></span>
Active
</span>
</td>
<td class="px-6 py-4 text-right">
<button onclick="openModal()" class="text-sm text-cyan-600 hover:text-cyan-800 font-medium transition-colors">View</button>
</td>
</tr>
<tr class="hover:bg-gray-50 transition-colors">
<td class="px-6 py-4">
<div class="flex items-center gap-3">
<div class="flex items-center justify-center w-9 h-9 bg-purple-100 text-purple-700 rounded-full text-sm font-bold">N</div>
<span class="text-sm font-medium text-gray-900">Nattaya P.</span>
</div>
</td>
<td class="px-6 py-4 text-sm text-gray-500">nattaya@example.com</td>
<td class="px-6 py-4 text-sm text-gray-500">Editor</td>
<td class="px-6 py-4">
<span class="inline-flex items-center gap-1 px-2.5 py-1 text-xs font-medium bg-green-50 text-green-700 rounded-full">
<span class="w-1.5 h-1.5 bg-green-500 rounded-full"></span>
Active
</span>
</td>
<td class="px-6 py-4 text-right">
<button onclick="openModal()" class="text-sm text-cyan-600 hover:text-cyan-800 font-medium transition-colors">View</button>
</td>
</tr>
<tr class="hover:bg-gray-50 transition-colors">
<td class="px-6 py-4">
<div class="flex items-center gap-3">
<div class="flex items-center justify-center w-9 h-9 bg-amber-100 text-amber-700 rounded-full text-sm font-bold">P</div>
<span class="text-sm font-medium text-gray-900">Prawit S.</span>
</div>
</td>
<td class="px-6 py-4 text-sm text-gray-500">prawit@example.com</td>
<td class="px-6 py-4 text-sm text-gray-500">Viewer</td>
<td class="px-6 py-4">
<span class="inline-flex items-center gap-1 px-2.5 py-1 text-xs font-medium bg-red-50 text-red-700 rounded-full">
<span class="w-1.5 h-1.5 bg-red-500 rounded-full"></span>
Inactive
</span>
</td>
<td class="px-6 py-4 text-right">
<button onclick="openModal()" class="text-sm text-cyan-600 hover:text-cyan-800 font-medium transition-colors">View</button>
</td>
</tr>
<tr class="hover:bg-gray-50 transition-colors">
<td class="px-6 py-4">
<div class="flex items-center gap-3">
<div class="flex items-center justify-center w-9 h-9 bg-green-100 text-green-700 rounded-full text-sm font-bold">M</div>
<span class="text-sm font-medium text-gray-900">Mayuree T.</span>
</div>
</td>
<td class="px-6 py-4 text-sm text-gray-500">mayuree@example.com</td>
<td class="px-6 py-4 text-sm text-gray-500">Editor</td>
<td class="px-6 py-4">
<span class="inline-flex items-center gap-1 px-2.5 py-1 text-xs font-medium bg-green-50 text-green-700 rounded-full">
<span class="w-1.5 h-1.5 bg-green-500 rounded-full"></span>
Active
</span>
</td>
<td class="px-6 py-4 text-right">
<button onclick="openModal()" class="text-sm text-cyan-600 hover:text-cyan-800 font-medium transition-colors">View</button>
</td>
</tr>
<tr class="hover:bg-gray-50 transition-colors">
<td class="px-6 py-4">
<div class="flex items-center gap-3">
<div class="flex items-center justify-center w-9 h-9 bg-cyan-100 text-cyan-700 rounded-full text-sm font-bold">W</div>
<span class="text-sm font-medium text-gray-900">Wichai R.</span>
</div>
</td>
<td class="px-6 py-4 text-sm text-gray-500">wichai@example.com</td>
<td class="px-6 py-4 text-sm text-gray-500">Admin</td>
<td class="px-6 py-4">
<span class="inline-flex items-center gap-1 px-2.5 py-1 text-xs font-medium bg-green-50 text-green-700 rounded-full">
<span class="w-1.5 h-1.5 bg-green-500 rounded-full"></span>
Active
</span>
</td>
<td class="px-6 py-4 text-right">
<button onclick="openModal()" class="text-sm text-cyan-600 hover:text-cyan-800 font-medium transition-colors">View</button>
</td>
</tr>
</tbody>
</table>
</div>
<!-- Mobile Cards (hidden on desktop) -->
<div class="md:hidden divide-y divide-gray-100">
<!-- Card 1 -->
<div class="flex items-center justify-between p-4 hover:bg-gray-50 transition-colors">
<div class="flex items-center gap-3 min-w-0">
<div class="flex items-center justify-center w-10 h-10 bg-blue-100 text-blue-700 rounded-full text-sm font-bold shrink-0">S</div>
<div class="min-w-0">
<p class="text-sm font-medium text-gray-900 truncate">Somchai K.</p>
<p class="text-xs text-gray-500 truncate">Admin</p>
</div>
</div>
<div class="flex items-center gap-3 shrink-0">
<span class="inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-green-50 text-green-700 rounded-full">Active</span>
<button onclick="openModal()" class="p-1.5 text-gray-400 hover:text-cyan-600 transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
</button>
</div>
</div>
<!-- Card 2 -->
<div class="flex items-center justify-between p-4 hover:bg-gray-50 transition-colors">
<div class="flex items-center gap-3 min-w-0">
<div class="flex items-center justify-center w-10 h-10 bg-purple-100 text-purple-700 rounded-full text-sm font-bold shrink-0">N</div>
<div class="min-w-0">
<p class="text-sm font-medium text-gray-900 truncate">Nattaya P.</p>
<p class="text-xs text-gray-500 truncate">Editor</p>
</div>
</div>
<div class="flex items-center gap-3 shrink-0">
<span class="inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-green-50 text-green-700 rounded-full">Active</span>
<button onclick="openModal()" class="p-1.5 text-gray-400 hover:text-cyan-600 transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
</button>
</div>
</div>
<!-- Card 3 -->
<div class="flex items-center justify-between p-4 hover:bg-gray-50 transition-colors">
<div class="flex items-center gap-3 min-w-0">
<div class="flex items-center justify-center w-10 h-10 bg-amber-100 text-amber-700 rounded-full text-sm font-bold shrink-0">P</div>
<div class="min-w-0">
<p class="text-sm font-medium text-gray-900 truncate">Prawit S.</p>
<p class="text-xs text-gray-500 truncate">Viewer</p>
</div>
</div>
<div class="flex items-center gap-3 shrink-0">
<span class="inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-red-50 text-red-700 rounded-full">Inactive</span>
<button onclick="openModal()" class="p-1.5 text-gray-400 hover:text-cyan-600 transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
</button>
</div>
</div>
<!-- Card 4 -->
<div class="flex items-center justify-between p-4 hover:bg-gray-50 transition-colors">
<div class="flex items-center gap-3 min-w-0">
<div class="flex items-center justify-center w-10 h-10 bg-green-100 text-green-700 rounded-full text-sm font-bold shrink-0">M</div>
<div class="min-w-0">
<p class="text-sm font-medium text-gray-900 truncate">Mayuree T.</p>
<p class="text-xs text-gray-500 truncate">Editor</p>
</div>
</div>
<div class="flex items-center gap-3 shrink-0">
<span class="inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-green-50 text-green-700 rounded-full">Active</span>
<button onclick="openModal()" class="p-1.5 text-gray-400 hover:text-cyan-600 transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
</button>
</div>
</div>
<!-- Card 5 -->
<div class="flex items-center justify-between p-4 hover:bg-gray-50 transition-colors">
<div class="flex items-center gap-3 min-w-0">
<div class="flex items-center justify-center w-10 h-10 bg-cyan-100 text-cyan-700 rounded-full text-sm font-bold shrink-0">W</div>
<div class="min-w-0">
<p class="text-sm font-medium text-gray-900 truncate">Wichai R.</p>
<p class="text-xs text-gray-500 truncate">Admin</p>
</div>
</div>
<div class="flex items-center gap-3 shrink-0">
<span class="inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-green-50 text-green-700 rounded-full">Active</span>
<button onclick="openModal()" class="p-1.5 text-gray-400 hover:text-cyan-600 transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
</button>
</div>
</div>
</div>
<!-- Table Footer / Pagination -->
<div class="flex items-center justify-between px-6 py-3 border-t border-gray-100 bg-gray-50/50">
<p class="text-sm text-gray-500">Showing 1-5 of 24 users</p>
<div class="flex items-center gap-1">
<button class="px-3 py-1.5 text-sm text-gray-500 hover:bg-gray-200 rounded-lg transition-colors">Prev</button>
<button class="px-3 py-1.5 text-sm font-medium bg-cyan-600 text-white rounded-lg">1</button>
<button class="px-3 py-1.5 text-sm text-gray-500 hover:bg-gray-200 rounded-lg transition-colors">2</button>
<button class="px-3 py-1.5 text-sm text-gray-500 hover:bg-gray-200 rounded-lg transition-colors">3</button>
<button class="px-3 py-1.5 text-sm text-gray-500 hover:bg-gray-200 rounded-lg transition-colors">Next</button>
</div>
</div>
</div>
</main>
</div>
</div>
<!-- ==================== MODAL ==================== -->
<div id="modal"
class="fixed inset-0 z-50 hidden items-center justify-center p-4">
<!-- Backdrop -->
<div class="fixed inset-0 bg-black/50 backdrop-blur-sm modal-backdrop"
onclick="closeModal()"></div>
<!-- Modal Panel -->
<div class="relative w-full max-w-lg bg-white rounded-2xl shadow-2xl
transform transition-all duration-300 modal-panel">
<!-- Close Button -->
<button onclick="closeModal()"
class="absolute top-4 right-4 p-1.5 text-gray-400 hover:text-gray-600
hover:bg-gray-100 rounded-lg transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
<!-- Modal Header -->
<div class="px-6 pt-6 pb-4">
<h3 class="text-lg font-bold text-gray-900">User Details</h3>
<p class="text-sm text-gray-500">View and manage user information</p>
</div>
<!-- Modal Body -->
<div class="px-6 pb-4">
<div class="flex items-center gap-4 p-4 bg-gray-50 rounded-xl mb-4">
<div class="flex items-center justify-center w-14 h-14 bg-blue-100 text-blue-700 rounded-full text-xl font-bold">
S
</div>
<div>
<p class="text-base font-bold text-gray-900">Somchai K.</p>
<p class="text-sm text-gray-500">somchai@example.com</p>
</div>
</div>
<div class="grid grid-cols-2 gap-4">
<div class="p-3 bg-gray-50 rounded-lg">
<p class="text-xs font-medium text-gray-500 uppercase mb-1">Role</p>
<p class="text-sm font-semibold text-gray-900">Admin</p>
</div>
<div class="p-3 bg-gray-50 rounded-lg">
<p class="text-xs font-medium text-gray-500 uppercase mb-1">Status</p>
<span class="inline-flex items-center gap-1 text-sm font-semibold text-green-700">
<span class="w-1.5 h-1.5 bg-green-500 rounded-full"></span>
Active
</span>
</div>
<div class="p-3 bg-gray-50 rounded-lg">
<p class="text-xs font-medium text-gray-500 uppercase mb-1">Joined</p>
<p class="text-sm font-semibold text-gray-900">Jan 15, 2024</p>
</div>
<div class="p-3 bg-gray-50 rounded-lg">
<p class="text-xs font-medium text-gray-500 uppercase mb-1">Last Active</p>
<p class="text-sm font-semibold text-gray-900">2 hours ago</p>
</div>
</div>
</div>
<!-- Modal Footer -->
<div class="flex items-center justify-end gap-3 px-6 py-4 border-t border-gray-100">
<button onclick="closeModal()"
class="px-4 py-2 text-sm font-medium text-gray-700 bg-gray-100 hover:bg-gray-200
rounded-lg transition-colors">
Close
</button>
<button class="px-4 py-2 text-sm font-medium text-white bg-cyan-600 hover:bg-cyan-700
rounded-lg transition-colors">
Edit User
</button>
</div>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
Show style.css
style.css
/* ==========================================
Admin Dashboard - Custom Styles
Tailwind CDN handles all utility classes.
This file is for custom animations only.
========================================== */
/* Smooth page transitions */
* {
scroll-behavior: smooth;
}
/* Modal animation */
.modal-backdrop {
animation: fadeIn 0.2s ease-out;
}
.modal-panel {
animation: slideUp 0.3s ease-out;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(16px) scale(0.96);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
/* Mobile sidebar slide-in */
#mobile-overlay aside {
animation: slideInLeft 0.3s ease-out;
}
@keyframes slideInLeft {
from { transform: translateX(-100%); }
to { transform: translateX(0); }
}
Show script.js
script.js
// ==========================================
// Admin Dashboard - JavaScript
// Handles: Mobile Sidebar, Modal
// ==========================================
// --- Mobile Sidebar ---
function openMobileSidebar() {
const overlay = document.getElementById('mobile-overlay');
overlay.classList.remove('hidden');
// Prevent body scroll when sidebar is open
document.body.style.overflow = 'hidden';
}
function closeMobileSidebar() {
const overlay = document.getElementById('mobile-overlay');
overlay.classList.add('hidden');
// Restore body scroll
document.body.style.overflow = '';
}
// --- Modal ---
function openModal() {
const modal = document.getElementById('modal');
modal.classList.remove('hidden');
modal.classList.add('flex');
// Prevent body scroll
document.body.style.overflow = 'hidden';
}
function closeModal() {
const modal = document.getElementById('modal');
modal.classList.add('hidden');
modal.classList.remove('flex');
// Restore body scroll
document.body.style.overflow = '';
}
// --- Keyboard Support ---
document.addEventListener('keydown', function (e) {
if (e.key === 'Escape') {
// Close modal if open
const modal = document.getElementById('modal');
if (!modal.classList.contains('hidden')) {
closeModal();
return;
}
// Close mobile sidebar if open
const overlay = document.getElementById('mobile-overlay');
if (!overlay.classList.contains('hidden')) {
closeMobileSidebar();
}
}
});
  1. Sidebar Navigation

    ใช้ hidden lg:flex เพื่อซ่อน sidebar บน mobile และแสดงบน desktop (1024px+) sidebar มี fixed inset-y-0 left-0 w-64 เพื่อยึดด้านซ้ายตลอด ส่วน main content ใช้ lg:ml-64 เพื่อเว้นที่ให้ sidebar

    Preview Output
    Admin
    Dashboard
    Users
    Products
    Settings
    fixed w-64
    lg:ml-64
    main content lg:ml-64
  2. Mobile Sidebar (Drawer)

    สร้าง overlay แยกสำหรับ mobile ใช้ fixed inset-0 z-50 ครอบทั้งจอ มี backdrop สีดำ semi-transparent (bg-black/50) และ drawer panel ที่เลื่อนเข้าจากซ้าย ควบคุม show/hide ด้วย JavaScript toggle class hidden

    Preview Output
    Dashboard
    bg-black/50
    Admin
    Dashboard
    Users
    Products
    drawer fixed z-50
  3. Data Table + Mobile Cards

    ใช้ hidden md:block สำหรับ table view บน desktop และ md:hidden สำหรับ card view บน mobile ทำให้ responsive โดยไม่ต้องเขียน CSS ซับซ้อน แค่สลับระหว่างสอง layout ด้วย Tailwind breakpoints

    Preview Output
    Desktop: hidden md:block
    NameRoleStatus
    S Somchai Admin Active
    N Nattaya Editor Active
    P Prawit Viewer Inactive
    Mobile: md:hidden
    S
    Somchai K.
    Admin
    Active
    N
    Nattaya P.
    Editor
    Active
    P
    Prawit S.
    Viewer
    Inactive
  4. Modal (Dialog)

    Modal ใช้ fixed inset-0 z-50 ครอบทั้งจอ มี backdrop กับ modal panel แยกกัน ใช้ JavaScript สลับ hidden/flex พร้อม CSS animations สำหรับ fade-in และ slide-up รองรับปิดด้วย Escape key ผ่าน keyboard event listener

    Preview Output
    Page Content (grayed out)
    Backdrop bg-black/50
    User Details
    Modal z-50 (top layer)
  5. Stats Cards

    ใช้ CSS Grid responsive grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 เพื่อแสดง 1 column บน mobile, 2 columns บน tablet, 4 columns บน desktop แต่ละ card มี hover effect ด้วย hover:shadow-md transition-shadow

    Preview Output
    grid-cols-1
    2,451 Users
    sm:grid-cols-2
    Users
    Revenue
    xl:grid-cols-4
    Users
    Revenue
    Orders
    Active
  6. Tailwind Patterns ที่ใช้

    ตลอดทั้งโปรเจกต์ใช้ pattern จาก shadcn/ui ได้แก่ Button variants (primary กับ ghost), Status badges ด้วย colored dots, Card layouts ที่มี border + rounded corners, และ consistent spacing system (p-4, p-6, gap-3, gap-4)

    Preview Output
    Button Variants
    Primary Secondary Ghost
    Status Badges
    Active Pending Inactive
    Card Pattern
    Card Title
    border + rounded-xl + shadow
  • ใช้ Tailwind CSS utility classes สร้าง layout จริงได้ (Sidebar, Table, Modal)
  • ทำ Responsive Design ด้วย Tailwind breakpoints (sm:, md:, lg:, xl:)
  • สร้าง shadcn/ui-style components ด้วย Tailwind (Button variants, Badges, Cards)
  • ใช้ JavaScript ควบคุม UI state (show/hide sidebar, modal)
  • เข้าใจ Design System patterns ผ่านโค้ดจริง (consistent spacing, colors, typography)