Common Patterns & Recipes

Copy-paste solutions for the patterns that show up in every admin dashboard. Each recipe assumes you’ve followed Getting Started and have a working AdminLTE page to build on.

A multi-level sidebar with icons, badges, and headers

The demo dashboards use this exact pattern. Group sections with .nav-header, indicate item depth with nested .nav-treeview lists, and use .navbar-badge for counts.

<aside class="app-sidebar bg-body-secondary shadow" data-bs-theme="dark">
  <div class="sidebar-brand">
    <a href="/" class="brand-link">
      <span class="brand-text fw-light">My Dashboard</span>
    </a>
  </div>
  <div class="sidebar-wrapper">
    <nav class="mt-2">
      <ul class="nav sidebar-menu flex-column" data-lte-toggle="treeview" role="menu">

        <li class="nav-header">MAIN</li>
        <li class="nav-item">
          <a href="/" class="nav-link active">
            <i class="nav-icon bi bi-speedometer"></i>
            <p>Dashboard</p>
          </a>
        </li>

        <li class="nav-item">
          <a href="#" class="nav-link">
            <i class="nav-icon bi bi-folder"></i>
            <p>
              Projects
              <span class="badge text-bg-info ms-2">12</span>
              <i class="nav-arrow bi bi-chevron-right"></i>
            </p>
          </a>
          <ul class="nav nav-treeview">
            <li class="nav-item">
              <a href="#" class="nav-link"><i class="nav-icon bi bi-circle"></i><p>Active</p></a>
            </li>
            <li class="nav-item">
              <a href="#" class="nav-link"><i class="nav-icon bi bi-circle"></i><p>Archived</p></a>
            </li>
          </ul>
        </li>

        <li class="nav-header">REPORTS</li>
        <li class="nav-item">
          <a href="#" class="nav-link">
            <i class="nav-icon bi bi-bar-chart"></i>
            <p>Sales</p>
            <span class="badge text-bg-danger ms-auto">3</span>
          </a>
        </li>

      </ul>
    </nav>
  </div>
</aside>

To mark the current page as active, server-render the .active class onto the matching .nav-link. For SPA frameworks, add it on route change.

Highlighting the active sidebar item from JavaScript

If you’re rendering the sidebar once and want client-side route highlighting:

function setActiveSidebarItem(href) {
  document.querySelectorAll(".sidebar-menu .nav-link").forEach((el) => {
    el.classList.toggle("active", el.getAttribute("href") === href)
  })
}

// Call on route change
setActiveSidebarItem(window.location.pathname)
Responsive data tables

Wrap a <table> in .table-responsive so it gets a horizontal scrollbar on narrow viewports instead of overflowing the card.

<div class="card">
  <div class="card-header">
    <h3 class="card-title">Recent orders</h3>
  </div>
  <div class="card-body p-0">
    <div class="table-responsive">
      <table class="table table-striped align-middle mb-0">
        <thead>
          <tr>
            <th>#</th>
            <th>Customer</th>
            <th>Total</th>
            <th>Status</th>
            <th class="text-end">Actions</th>
          </tr>
        </thead>
        <tbody>
          <!-- rows -->
        </tbody>
      </table>
    </div>
  </div>
</div>

For interactive sorting/filtering/pagination, use Tabulatortables/data.html in the demo has a full example.

A user dropdown in the topbar
<li class="nav-item dropdown user-menu">
  <a href="#" class="nav-link dropdown-toggle" data-bs-toggle="dropdown">
    <span class="d-none d-md-inline me-1">Jane Doe</span>
    <i class="bi bi-person-circle fs-5"></i>
  </a>
  <ul class="dropdown-menu dropdown-menu-end">
    <li>
      <a href="/profile" class="dropdown-item">
        <i class="bi bi-person me-2"></i>Profile
      </a>
    </li>
    <li>
      <a href="/settings" class="dropdown-item">
        <i class="bi bi-gear me-2"></i>Settings
      </a>
    </li>
    <li><hr class="dropdown-divider"></li>
    <li>
      <a href="/logout" class="dropdown-item text-danger">
        <i class="bi bi-box-arrow-right me-2"></i>Sign out
      </a>
    </li>
  </ul>
</li>

Put this inside the <ul class="navbar-nav ms-auto"> in .app-header.

A KPI card (small-box)

The bright-coloured stat boxes at the top of most dashboards:

<div class="row g-3">
  <div class="col-lg-3 col-6">
    <div class="small-box text-bg-primary">
      <div class="inner">
        <h3>150</h3>
        <p>New orders</p>
      </div>
      <i class="bi bi-cart small-box-icon" aria-hidden="true"></i>
      <a href="#" class="small-box-footer link-light">
        More info <i class="bi bi-arrow-right"></i>
      </a>
    </div>
  </div>
  <!-- repeat 3 more times with different values + colours -->
</div>

Swap text-bg-primary for text-bg-success, text-bg-warning, text-bg-danger, etc.

A breadcrumb + page-title row

This is the standard .app-content-header pattern used across every demo page:

<div class="app-content-header">
  <div class="container-fluid">
    <div class="row">
      <div class="col-sm-6">
        <h3 class="mb-0">Page Title</h3>
      </div>
      <div class="col-sm-6">
        <ol class="breadcrumb float-sm-end">
          <li class="breadcrumb-item"><a href="/">Home</a></li>
          <li class="breadcrumb-item"><a href="/section">Section</a></li>
          <li class="breadcrumb-item active" aria-current="page">Current page</li>
        </ol>
      </div>
    </div>
  </div>
</div>
A timeline

For activity feeds, audit logs, or roadmap views:

<div class="timeline">
  <div>
    <i class="bi bi-envelope bg-info" aria-hidden="true"></i>
    <div class="timeline-item">
      <span class="time"><i class="bi bi-clock"></i> 12:05</span>
      <h3 class="timeline-header">
        <a href="#">Olivia</a> sent you a message
      </h3>
      <div class="timeline-body">
        Hey, can we review the Q4 numbers tomorrow at 10?
      </div>
      <div class="timeline-footer">
        <a class="btn btn-primary btn-sm">Read more</a>
      </div>
    </div>
  </div>
  <!-- repeat -->
</div>

The timeline component lives in _timeline.scss and has variants. See /UI/timeline.html for the full set.

A direct-chat widget

The chat-style card used for live customer support, team chat, etc. Includes contact toggle and message bubbles.

<div class="card direct-chat direct-chat-primary">
  <div class="card-header">
    <h3 class="card-title">Direct Chat</h3>
    <div class="card-tools">
      <span class="badge text-bg-primary">3 new</span>
      <button type="button" class="btn btn-tool" data-lte-toggle="chat-pane" title="Contacts">
        <i class="bi bi-people-fill"></i>
      </button>
    </div>
  </div>
  <div class="card-body">
    <div class="direct-chat-messages">
      <div class="direct-chat-msg">
        <div class="direct-chat-infos clearfix">
          <span class="direct-chat-name float-start">Olivia</span>
          <span class="direct-chat-timestamp float-end">12:05</span>
        </div>
        <img class="direct-chat-img" src="/avatars/olivia.jpg" alt="" />
        <div class="direct-chat-text">Hey, ready for the review?</div>
      </div>
      <div class="direct-chat-msg right">
        <div class="direct-chat-infos clearfix">
          <span class="direct-chat-name float-end">You</span>
          <span class="direct-chat-timestamp float-start">12:06</span>
        </div>
        <img class="direct-chat-img" src="/avatars/me.jpg" alt="" />
        <div class="direct-chat-text">Yes, on my way.</div>
      </div>
    </div>
    <div class="direct-chat-contacts">
      <!-- contacts list, shown when chat-pane toggled -->
    </div>
  </div>
  <div class="card-footer">
    <form>
      <div class="input-group">
        <input type="text" class="form-control" placeholder="Message…" />
        <button type="submit" class="btn btn-primary">
          <i class="bi bi-send"></i>
        </button>
      </div>
    </form>
  </div>
</div>

For a full-page chat application, see /pages/chat.html in the demo.

Reacting to layout/sidebar changes

Listen for plugin events to coordinate with your own code — e.g., refit a chart when the sidebar collapses (so the chart re-measures its container width):

let chart = /* your ApexCharts instance */

document.addEventListener("collapse.lte.push-menu", () => {
  // wait for the transition to finish (~300ms by default)
  setTimeout(() => chart.updateOptions({}), 350)
})

document.addEventListener("open.lte.push-menu", () => {
  setTimeout(() => chart.updateOptions({}), 350)
})

The same pattern works for Tabulator, FullCalendar, and any other library that reads its container width on init.

Loading content into a card via fetch
<div class="card" id="users-card">
  <div class="card-header">
    <h3 class="card-title">Users</h3>
    <div class="card-tools">
      <span class="spinner-border spinner-border-sm text-secondary d-none" id="users-spinner" role="status"></span>
    </div>
  </div>
  <div class="card-body p-0">
    <div id="users-body" class="text-secondary p-3">Loading&hellip;</div>
  </div>
</div>

<script>
  const spinner = document.getElementById("users-spinner")
  const body = document.getElementById("users-body")

  spinner.classList.remove("d-none")
  fetch("/api/users")
    .then((r) => r.text())
    .then((html) => { body.innerHTML = html })
    .catch(() => { body.textContent = "Failed to load." })
    .finally(() => spinner.classList.add("d-none"))
</script>
Confirming destructive actions before submission

Bootstrap modal + a tiny confirmation pattern:

<button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#confirmDelete">
  Delete account
</button>

<div class="modal fade" id="confirmDelete" tabindex="-1">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title">Delete account?</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
      </div>
      <div class="modal-body">
        This permanently deletes your account and all associated data. This cannot be undone.
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
        <form action="/account/delete" method="POST" class="d-inline">
          <button type="submit" class="btn btn-danger">Yes, delete it</button>
        </form>
      </div>
    </div>
  </div>
</div>

The Color Mode, Accessibility, and the bundled JS handle Escape-to-close, focus trap, and keyboard navigation inside the modal automatically.

Where to next