Blog

Blog · Templates

Free Admin Dashboard Template (HTML & CSS, 2026)

A responsive admin dashboard template in HTML and CSS — sidebar navigation, top bar, stat cards and a data table — using CSS Grid, accessible and easy to extend.

XCODX Team · 4 min read

This free admin dashboard template is a responsive back-office layout in plain HTML and CSS: a sidebar for navigation, a top bar, a row of stat cards and a data table. It uses CSS Grid for the shell, collapses gracefully on mobile, and is themed with CSS variables so you can drop in your brand and data.

What you get

  • A CSS Grid app shell: sidebar + top bar + scrollable main content.
  • A responsive stat-card row and a clean, accessible data table.
  • Mobile-friendly — the sidebar stacks above the content on small screens.
  • CSS-variable theming and no dependencies.

The HTML

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Dashboard</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <div class="app">
    <aside class="sidebar">
      <div class="brand">Acme</div>
      <nav aria-label="Main">
        <a href="#" aria-current="page">Overview</a>
        <a href="#">Customers</a>
        <a href="#">Orders</a>
        <a href="#">Products</a>
        <a href="#">Settings</a>
      </nav>
    </aside>

    <div class="main">
      <header class="topbar">
        <h1>Overview</h1>
        <div class="user">Jane Doe</div>
      </header>

      <section class="content">
        <div class="stats">
          <div class="stat"><span class="label">Revenue</span><span class="value">$48.2k</span><span class="delta up">+12%</span></div>
          <div class="stat"><span class="label">Orders</span><span class="value">1,284</span><span class="delta up">+4%</span></div>
          <div class="stat"><span class="label">Customers</span><span class="value">3,910</span><span class="delta up">+8%</span></div>
          <div class="stat"><span class="label">Refunds</span><span class="value">$1.1k</span><span class="delta down">-2%</span></div>
        </div>

        <div class="panel">
          <h2>Recent orders</h2>
          <table>
            <thead>
              <tr><th scope="col">Order</th><th scope="col">Customer</th><th scope="col">Status</th><th scope="col">Total</th></tr>
            </thead>
            <tbody>
              <tr><td>#1042</td><td>Ada Lovelace</td><td><span class="tag ok">Paid</span></td><td>$120</td></tr>
              <tr><td>#1041</td><td>Alan Turing</td><td><span class="tag pending">Pending</span></td><td>$80</td></tr>
              <tr><td>#1040</td><td>Grace Hopper</td><td><span class="tag ok">Paid</span></td><td>$260</td></tr>
            </tbody>
          </table>
        </div>
      </section>
    </div>
  </div>
</body>
</html>

The CSS

:root {
  --bg: #0b0d14; --surface: #141824; --sidebar: #0e1119; --text: #e8ecf4;
  --muted: #9aa4b8; --accent: #6ea8ff; --border: #232838; --ok: #46d07f; --warn: #ffbd2e;
  color-scheme: dark;
}
* { box-sizing: border-box; margin: 0; }
body { font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  background: var(--bg); color: var(--text); }

.app { display: grid; grid-template-columns: 240px 1fr; min-height: 100vh; }
.main { min-width: 0; }  /* let the grid item shrink so the table scrolls inside its panel, not the page */
.sidebar { background: var(--sidebar); border-right: 1px solid var(--border); padding: 20px; }
.brand { font-weight: 800; font-size: 20px; margin-bottom: 24px; }
.sidebar nav { display: flex; flex-direction: column; gap: 4px; }
.sidebar a { color: var(--muted); text-decoration: none; padding: 10px 12px; border-radius: 8px; }
.sidebar a:hover { color: var(--text); background: var(--surface); }
.sidebar a[aria-current="page"] { color: var(--text); background: var(--surface); }

.topbar { display: flex; justify-content: space-between; align-items: center;
  padding: 18px 24px; border-bottom: 1px solid var(--border); }
.topbar h1 { font-size: 20px; }
.user { color: var(--muted); font-size: 14px; }
.content { padding: 24px; }

.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 16px; }
.stat { background: var(--surface); border: 1px solid var(--border); border-radius: 14px; padding: 18px;
  display: flex; flex-direction: column; gap: 4px; }
.label { color: var(--muted); font-size: 13px; }
.value { font-size: 24px; font-weight: 700; }
.delta { font-size: 13px; font-weight: 600; }
.delta.up { color: var(--ok); } .delta.down { color: var(--warn); }

.panel { background: var(--surface); border: 1px solid var(--border); border-radius: 14px;
  padding: 20px; margin-top: 20px; overflow-x: auto; }
.panel h2 { font-size: 16px; margin-bottom: 14px; }
table { width: 100%; border-collapse: collapse; min-width: 460px; }
th, td { text-align: left; padding: 12px 10px; border-bottom: 1px solid var(--border); font-size: 14px; }
th { color: var(--muted); font-weight: 600; }
.tag { font-size: 12px; padding: 3px 10px; border-radius: 20px; }
.tag.ok { background: rgba(70,208,127,.15); color: var(--ok); }
.tag.pending { background: rgba(255,189,46,.15); color: var(--warn); }

@media (max-width: 760px) {
  .app { grid-template-columns: 1fr; }
  .sidebar { border-right: 0; border-bottom: 1px solid var(--border); }
  .sidebar nav { flex-direction: row; flex-wrap: wrap; }
}

How to extend it

  • Add pages: each sidebar link points to a route; render different content in .content per page.
  • Real data: replace the static table rows and stats with data fetched from your API — see best HTTP client libraries.
  • Charts: drop a chart into a .panel using a charting library.
  • Collapsible sidebar: add a toggle button and a class that narrows the grid’s first column for a slide-in menu.
  • Framework version: to make it interactive, rebuild it in React with a starter template and a UI component library.

Frequently asked questions

How is the dashboard layout built?
The app shell is a CSS Grid with two columns — a fixed 240px sidebar and a fluid main area (grid-template-columns: 240px 1fr) — spanning the full viewport height. Inside, the stat cards and table use their own grids and standard flow. On small screens a media query collapses it to a single column and turns the sidebar into a horizontal nav.
Is the data table accessible?
Yes. It uses proper <table> semantics with <thead>, <th scope="col"> header cells, and <tbody> rows, which screen readers announce correctly. The table sits in a container with overflow-x: auto so it scrolls horizontally on narrow screens instead of breaking the layout.
Can I make the sidebar collapsible?
Yes. Add a toggle button that switches a class on the .app element, and in CSS change the grid’s first column (for example to a narrow icon rail or 0) when that class is present. For a mobile slide-in menu, position the sidebar fixed and translate it in and out with a transform.
How do I add real data to the dashboard?
Fetch it from your backend and render the rows and stats dynamically. In plain JavaScript, request the data with fetch and build the table with template strings or DOM methods. For a larger app, rebuild the dashboard in a framework like React and use a data-fetching library such as TanStack Query to handle loading and caching.

Open this dashboard in XCODX Studio to edit it live. See also the React starter template, best charting libraries and the complete guide to CSS Grid.