Layout
Every AdminLTE 4 page follows the same skeleton: an .app-wrapper CSS-grid container holding a header, sidebar, main content region, and an optional footer. Body-level classes control fixed positioning and the responsive sidebar breakpoint.
The page skeleton
The four region classes inside .app-wrapper are positioned as grid areas — their order in the markup doesn't matter, the grid template places each by its class.
<body class="layout-fixed sidebar-expand-lg bg-body-tertiary">
<div class="app-wrapper">
<!-- Header -->
<nav class="app-header navbar navbar-expand bg-body">
<div class="container-fluid">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" data-lte-toggle="sidebar" href="#" role="button">
<i class="bi bi-list"></i>
</a>
</li>
</ul>
</div>
</nav>
<!-- Sidebar -->
<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">
<!-- nav items -->
</ul>
</nav>
</div>
</aside>
<!-- Main content -->
<main class="app-main">
<div class="app-content-header">
<div class="container-fluid">
<div class="row">
<div class="col-sm-6"><h3 class="mb-0">Dashboard</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 active" aria-current="page">Dashboard</li>
</ol>
</div>
</div>
</div>
</div>
<div class="app-content">
<div class="container-fluid">
<!-- page body: cards, tables, charts -->
</div>
</div>
</main>
<!-- Footer -->
<footer class="app-footer">
<div class="float-end d-none d-sm-inline">Anything you want</div>
<strong>Copyright © 2026 <a href="#">Your Company</a>.</strong>
</footer>
</div>
</body>
The four regions
| Class | Role |
|---|---|
.app-wrapper | The grid root. Defines header / sidebar / main / footer areas. Lives directly inside <body>. |
.app-header | The top bar. Use Bootstrap navbar classes (navbar navbar-expand bg-body). Houses the sidebar toggle. |
.app-sidebar | The side rail. Always contains .sidebar-brand and .sidebar-wrapper. |
.app-main | The content region — contains .app-content-header (title strip) and .app-content (page body). |
.app-footer | Optional footer strip at the bottom of the wrapper. |
Always wrap children of .app-content-header and .app-content in .container-fluid (or .container for capped width). Forgetting it makes content land flush against the screen edge.
Body layout option classes
Layout behaviour is controlled by classes on <body>:
| Class | Effect |
|---|---|
layout-fixed | Sidebar gets its own scrollbar; only .app-main scrolls with the page. |
fixed-header | Pins .app-header to the top; the sidebar pins too. |
fixed-footer | Pins .app-footer to the bottom of the viewport. |
sidebar-expand-{sm,md,lg,xl,xxl} | Breakpoint at which the sidebar switches from off-canvas (mobile) to inline (desktop). lg is the demo default. |
sidebar-mini | Collapses the sidebar to an icon-only mini state. |
sidebar-collapse | Combined with sidebar-mini, starts the page with the mini sidebar already collapsed. |
sidebar-without-hover | Disables auto-expand-on-hover for the mini sidebar. |
layout-rtl | Mirrors the layout for right-to-left languages (also needs adminlte.rtl.css and dir="rtl"). |
These compose. The demo dashboards use class="layout-fixed sidebar-expand-lg bg-body-tertiary".
Responsive behaviour
At and above the sidebar-expand-* breakpoint, the sidebar is inline in the grid. Below it, the sidebar becomes off-canvas — hidden by default and slid in from the left on toggle. The sidebar-open (explicitly opened) and sidebar-collapse (closed) classes are managed automatically by the PushMenu plugin via data-lte-toggle="sidebar" — you don't write them yourself.
Don't mix .app-* classes with AdminLTE 3's .main-* naming (.wrapper, .main-header, etc.). They are not interchangeable.