AdminLTE is a free, MIT-licensed admin dashboard template built on Bootstrap 5.3 with vanilla TypeScript — no jQuery. It gives you a responsive application shell (header, collapsible sidebar, content area, footer), light/dark/auto color modes, RTL support, seven ready-to-use JavaScript plugins, and a catalog of demo pages. You drop the markup into your own project and customize the parts you need.
This guide takes you from a blank HTML file to a working, customized dashboard. It is written for the people who build dashboards with AdminLTE: front-end developers, full-stack engineers wiring AdminLTE into a Laravel/Django/Rails view, and anyone integrating the template into an existing app.
Note
AdminLTE is a template, not a component library. Bootstrap 5 supplies the components (buttons, cards, modals, forms); AdminLTE supplies the application shell that wraps them — the wrapper grid, the sidebar system, the color-mode plumbing, and the dashboard widgets. If you already know Bootstrap 5, you already know 80% of AdminLTE.
Table of Contents
- Quick Start
- Installation
- The Layout System
- Building the Sidebar Navigation
- JavaScript Plugins
- Color Modes (Light / Dark / Auto)
- Customizing the Look
- Common Recipes
- Adding Third-Party Widgets
- Right-to-Left (RTL) Layouts
- Upgrading from AdminLTE 3
- Troubleshooting
- FAQ
- Reference
1. Quick Start
AdminLTE is an HTML template — there is no build step required to use it. You can have a working dashboard in about ten minutes using a CDN, without npm, without a bundler, and without learning the project's internal Astro tooling.
Step 1 — Add the CDN tags
Create a new HTML file. Put these four stylesheet tags in <head>. They pull AdminLTE, Bootstrap 5.3, OverlayScrollbars, and Bootstrap Icons from jsDelivr:
<!-- In <head> -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.1/font/bootstrap-icons.min.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/overlayscrollbars@2.11.0/styles/overlayscrollbars.min.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/admin-lte@4.0.0/dist/css/adminlte.min.css" />
Put these four script tags just before </body>:
<!-- Before </body> -->
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/overlayscrollbars@2.11.0/browser/overlayscrollbars.browser.es6.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/admin-lte@4.0.0/dist/js/adminlte.min.js"></script>
Important
Load order matters. AdminLTE's CSS imports Bootstrap's CSS, and AdminLTE's JavaScript must load after Bootstrap and Popper. Keep the script order exactly as shown above or interactive behavior breaks silently.
Step 2 — Drop in the minimum viable layout
This is the smallest page that still feels like AdminLTE — a header, a collapsible sidebar, and a content area. Place it inside <body>, between the CSS and JS tags:
<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">
<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-bar-chart"></i>
<p>Reports</p>
</a>
</li>
</ul>
</nav>
</div>
</aside>
<!-- Main content -->
<main class="app-main">
<div class="app-content-header">
<div class="container-fluid">
<h3 class="mb-0">Hello, AdminLTE</h3>
</div>
</div>
<div class="app-content">
<div class="container-fluid">
<div class="card">
<div class="card-header"><h5 class="card-title">Welcome</h5></div>
<div class="card-body">
Edit this file to start building your dashboard.
</div>
</div>
</div>
</div>
</main>
</div>
</body>
Step 3 — Open it
Open the file in any modern browser. You should see a dashboard with a dark sidebar on a light page. Click the hamburger button (bi-list) at the top-left — the sidebar collapses. That is AdminLTE's PushMenu plugin working out of the box, wired entirely by the data-lte-toggle="sidebar" attribute. No JavaScript code of your own is needed.
Tip
Every interactive feature in AdminLTE works the same way: add a
data-lte-toggle="..."attribute to a trigger element and the bundled JavaScript wires it on page load. You only write JavaScript when you want programmatic control (see Section 5).
What's actually happening
Four classes do the heavy lifting:
| Class | What it does |
|---|---|
app-wrapper |
The CSS-grid root — defines the header / sidebar / main / footer regions |
app-header |
The top navbar; pinned to the top of the viewport when layout-fixed is on <body> |
app-sidebar |
The collapsible side rail; sidebar-expand-lg on <body> sets its breakpoint |
app-main |
The scrollable content region — everything else lives here |
The next sections explain each of these in full.
2. Installation
You have four installation paths. Pick the one that matches how you'll actually use AdminLTE.
| Path | Best for | Setup time |
|---|---|---|
| CDN | Prototyping, demos, simple sites | 1 minute |
| npm + bundler | Production apps, framework projects (Laravel, Symfony, Rails) | 5 minutes |
| Build from source | Customizing SCSS variables (sidebar width, breakpoints, brand colors) | 10 minutes |
| Composer | PHP projects that prefer Packagist over npm | 2 minutes |
Prerequisites
| Minimum | Recommended | |
|---|---|---|
| Bootstrap | 5.3.0 | 5.3.8 (pinned in package.json) |
| Node.js | 18 LTS | 22 LTS (used by the project's CI) |
| Browser | Modern evergreen | Latest stable Chrome / Firefox / Safari / Edge |
Warning
AdminLTE 4 does not support Internet Explorer. If you need IE 11, stay on AdminLTE 3 or earlier — that constraint is not reversible in v4.
CDN — the fastest path
Use the tags from Quick Start. No install, no build step. Then copy any demo page's HTML into your own file and edit it. This is ideal for prototypes and simple internal tools.
npm + bundler
Requires Node.js 18+ and a bundler (Vite, Webpack, Rollup, esbuild, etc.).
npm
npm install admin-lte@4.0.0
yarn
yarn add admin-lte@4.0.0
pnpm
pnpm add admin-lte@4.0.0
Then import the CSS and JS in your app's entry point:
// CSS
import "admin-lte/dist/css/adminlte.min.css"
// Plus Bootstrap and dependency CSS
import "bootstrap-icons/font/bootstrap-icons.css"
import "overlayscrollbars/styles/overlayscrollbars.css"
// JS
import "bootstrap"
import "admin-lte"
Build from source
Choose this if you want to change SCSS variables — sidebar width, breakpoints, brand colors — which CSS custom properties can't reach.
git clone https://github.com/ColorlibHQ/AdminLTE.git
cd AdminLTE
npm install
npm run dev # dev server with hot-reload at http://localhost:3000
npm run production # one-off production build (clean + lint + compile)
The compiled output lands in dist/. Edit src/scss/_variables.scss or src/scss/_bootstrap-variables.scss, then rerun the build. See Customizing the Look for which variables matter.
Composer (PHP)
composer require "almasaeed2010/adminlte=4.0.0"
The Packagist package is published from the same source tree — you get the dist/ folder ready to serve.
Note
Whatever path you choose, the runtime artifacts are always the same two files:
dist/css/adminlte.min.cssanddist/js/adminlte.min.js, plus their Bootstrap and icon dependencies. AdminLTE doesn't bundle Bootstrap, Popper, OverlayScrollbars, or the icon font — you load those alongside it.
3. The Layout System
Every AdminLTE page follows the same blueprint: a wrapper containing a header, a sidebar, a main content area, and an optional footer.
The four regions
┌──────────────────────────────────────────┐
│ .app-wrapper │
│ ┌────────────────────────────────────┐ │
│ │ .app-header │ │ ← topbar / navbar
│ ├──────────┬─────────────────────────┤ │
│ │ │ │ │
│ │ .app- │ .app-main │ │ ← page content
│ │ sidebar │ │ │
│ │ │ │ │
│ ├──────────┴─────────────────────────┤ │
│ │ .app-footer (optional) │ │
│ └────────────────────────────────────┘ │
└──────────────────────────────────────────┘
.app-wrapper is a CSS-grid container; the four children are grid areas positioned by their class. Order inside .app-wrapper doesn't matter — the grid template places each child by its class, so use whatever order reads cleanly.
Minimal structure
<body class="layout-fixed sidebar-expand-lg bg-body-tertiary">
<div class="app-wrapper">
<nav class="app-header navbar navbar-expand bg-body">…</nav>
<aside class="app-sidebar bg-body-secondary shadow" data-bs-theme="dark">…</aside>
<main class="app-main">…</main>
<footer class="app-footer">…</footer>
</div>
</body>
Region reference
.app-wrapper
The root container; defines the grid that positions header, sidebar, main, and footer. Always lives directly inside <body>. Add .compact-mode here (or anywhere up the tree) to reduce padding throughout the layout — useful for data-dense dashboards.
.app-header
The top bar. Use Bootstrap's navbar classes (navbar navbar-expand bg-body) for the visuals. This is where the sidebar toggle button lives:
<a class="nav-link" data-lte-toggle="sidebar" href="#" role="button">
<i class="bi bi-list"></i>
</a>
By default the header scrolls with the page. Add .fixed-header to <body> to pin it.
.app-sidebar
The side rail. It always contains two children — .sidebar-brand (logo / app name) and .sidebar-wrapper (the scrollable nav region):
<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>
The data-bs-theme="dark" attribute on the sidebar gives the dark-sidebar-on-light-page look from the demos. Drop it for a light sidebar.
.app-main
The page content region. It almost always contains two children:
<main class="app-main">
<div class="app-content-header">
<!-- page title + breadcrumb -->
</div>
<div class="app-content">
<!-- page body: cards, tables, charts, etc. -->
</div>
</main>
.app-content-header is the title strip — typically an <h3> and a breadcrumb. .app-content is everything below it. Wrap the children of both in .container-fluid (or .container for capped width).
.app-footer (optional)
A footer strip at the bottom of the wrapper:
<footer class="app-footer">
<div class="float-end d-none d-sm-inline">Version 4.0.0</div>
<strong>© 2026 Your Company</strong>
</footer>
Add .fixed-footer to <body> to pin it.
Body-level layout modifiers
Layout behavior is controlled mostly by classes on <body>, not on .app-wrapper:
| Class | What it does |
|---|---|
layout-fixed |
Sidebar gets its own scrollbar; only .app-main scrolls with the page |
fixed-header |
Sticky .app-header; the sidebar also pins (new in v4.0.0) |
fixed-footer |
Sticky .app-footer at the bottom |
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-mini sidebar-collapse |
Starts the page with the mini sidebar already collapsed |
sidebar-without-hover |
Disables the auto-expand-on-hover behavior for the mini sidebar |
layout-rtl |
Mirrors the layout for right-to-left languages (also needs .rtl.css + dir="rtl"; see Section 10) |
These compose. The demo dashboards use class="layout-fixed sidebar-expand-lg bg-body-tertiary".
Responsive behavior
At and above your sidebar-expand-* breakpoint the sidebar is inline — visible in the grid alongside .app-main. Below the breakpoint it becomes off-canvas — hidden, and slid in from the left when the user taps the hamburger. The PushMenu plugin manages this automatically.
Tip
The eleven prebuilt layout combinations live in the demo's
layout/folder (fixed-sidebar,fixed-header,fixed-footer,fixed-complete,unfixed-sidebar,sidebar-mini,collapsed-sidebar,collapsed-sidebar-without-hover,layout-custom-area,logo-switch,layout-rtl). Open the matching demo page to see each modifier in isolation.
Common pitfalls
Caution
- Forgetting
.container-fluidinside.app-content— content lands flush against the screen edge. Always wrap content in a container.- Mixing
.app-*and.main-*classes —.main-*is the AdminLTE 3 naming. Don't combine them (see Section 11).- Using
position: fixedon something inside.app-main— withlayout-fixed,.app-mainalready hasoverflow: auto. Use sticky positioning instead.- Hardcoding sidebar width in custom CSS — the width is the SCSS variable
$lte-sidebar-width. If you need it in JavaScript, read the computed width of the.app-sidebarelement.
4. Building the Sidebar Navigation
The sidebar's nav menu is powered by the Treeview plugin. Add data-lte-toggle="treeview" to the parent <ul>, mark items with .nav-item, and put any submenu in a nested <ul class="nav-treeview">.
A single-level menu
<ul class="nav sidebar-menu flex-column" data-lte-toggle="treeview" role="menu">
<li class="nav-item">
<a class="nav-link active" href="/">
<i class="nav-icon bi bi-speedometer"></i>
<p>Dashboard</p>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/reports">
<i class="nav-icon bi bi-bar-chart"></i>
<p>Reports</p>
</a>
</li>
</ul>
Mark the current page with .active on its .nav-link. For server-rendered apps, add it in your template; for SPAs, toggle it on route change (see the recipe below).
A multi-level (collapsible) menu
Add a .nav-arrow chevron and a nested .nav-treeview list. The chevron rotates when the submenu opens:
<li class="nav-item">
<a href="#" class="nav-link">
<i class="nav-icon bi bi-folder"></i>
<p>
Reports
<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>Sales</p></a>
</li>
<li class="nav-item">
<a href="#" class="nav-link"><i class="nav-icon bi bi-circle"></i><p>Traffic</p></a>
</li>
</ul>
</li>
To start with a submenu already expanded, add menu-open to its .nav-item.
Section headers and badges
Group sections with .nav-header and show counts with a Bootstrap badge:
<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>
Accordion vs. multi-open
By default the treeview is an accordion — opening one submenu closes its siblings. To allow multiple submenus open at once, set data-accordion="false" on the parent <ul>:
<ul class="nav sidebar-menu" data-lte-toggle="treeview" data-accordion="false">
…
</ul>
You can also tune the slide animation. Default is 300 ms; set 0 to disable:
<ul class="nav sidebar-menu" data-lte-toggle="treeview" data-animation-speed="150">
…
</ul>
| Attribute | Default | Description |
|---|---|---|
data-accordion |
true |
Close other open submenus when one opens |
data-animation-speed |
300 |
Slide animation duration in milliseconds (0 disables) |
5. JavaScript Plugins
AdminLTE ships seven JavaScript plugins as a single bundle (adminlte.js). Each one can be triggered declaratively with a data-lte-* attribute (no code needed) and also exposes a programmatic API for code-driven control.
| Plugin | Data API trigger | What it does |
|---|---|---|
| PushMenu | data-lte-toggle="sidebar" |
Collapse / expand the sidebar |
| Treeview | data-lte-toggle="treeview" (on the parent menu) |
Expand / collapse sidebar submenus |
| CardWidget | data-lte-toggle="card-collapse", card-remove, card-maximize |
Collapse, remove, or maximize a card |
| DirectChat | data-lte-toggle="chat-pane" |
Toggle the contacts pane of a chat widget |
| FullScreen | data-lte-toggle="fullscreen" |
Toggle native browser fullscreen |
| Layout | (auto-applied to <body>) |
Manage transitions during resize; signal "app loaded" |
| AccessibilityManager | (auto-initialized) | WCAG 2.1 AA features (see Section 5.7) |
Two ways to use a plugin
1. Data API (declarative) — for most pages this is all you need. Drop the right attribute on the trigger and the bundle wires it up on DOMContentLoaded:
<button data-lte-toggle="sidebar">☰</button>
2. Programmatic (imperative) — when you need to control a plugin from your own code (e.g. open the sidebar after login, expand a card on a route change), instantiate the class directly. All seven are exported from the package root:
// ESM (bundler import)
import { PushMenu, CardWidget, Treeview } from "admin-lte"
new PushMenu(document.body, {}).expand()
const card = document.querySelector("#chart-card")
new CardWidget(card, {}).maximize()
Or via the global the UMD bundle assigns:
<script>
// The bundle assigns to window.adminlte
new adminlte.PushMenu(document.body, {}).expand()
</script>
Note
The bundle attaches all data-API listeners on
DOMContentLoaded. PushMenu, CardWidget, and Treeview use event delegation, so dynamically-injected elements still work after page load.
Listening to plugin events
Every plugin fires an event on the element it operates on. All events bubble, so you can listen on document:
document.addEventListener("expanded.lte.card-widget", (e) => {
console.log("Card expanded:", e.target)
})
document.addEventListener("open.lte.push-menu", () => {
// user opened the sidebar — e.g. an analytics call
})
| Plugin | Event | Fired when |
|---|---|---|
| PushMenu | open.lte.push-menu |
Sidebar expanded |
| PushMenu | collapse.lte.push-menu |
Sidebar collapsed |
| Treeview | expanded.lte.treeview |
Submenu opened |
| Treeview | collapsed.lte.treeview |
Submenu closed |
| Treeview | load.lte.treeview |
A pre-opened submenu was detected on page load |
| CardWidget | expanded.lte.card-widget |
Card body expanded |
| CardWidget | collapsed.lte.card-widget |
Card body collapsed |
| CardWidget | remove.lte.card-widget |
Card removed |
| CardWidget | maximized.lte.card-widget |
Card maximized |
| CardWidget | minimized.lte.card-widget |
Card restored from maximized |
| DirectChat | expanded.lte.direct-chat |
Contacts pane opened |
| DirectChat | collapsed.lte.direct-chat |
Contacts pane closed |
| FullScreen | maximized.lte.fullscreen |
Entered fullscreen |
| FullScreen | minimized.lte.fullscreen |
Exited fullscreen |
5.1 PushMenu — the sidebar
Toggles the sidebar between expanded and collapsed, handling responsive behavior, optional localStorage persistence, and the mobile overlay.
Data API:
<a href="#" data-lte-toggle="sidebar">Toggle Sidebar</a>
Configuration (data attributes on the .app-sidebar element):
| Attribute | Default | Description |
|---|---|---|
data-sidebar-breakpoint |
992 |
Screen width (px) below which the sidebar is treated as mobile |
data-enable-persistence |
false |
Save sidebar state to localStorage across page loads |
<aside class="app-sidebar" data-enable-persistence="true" data-sidebar-breakpoint="768">
…
</aside>
When persistence is on, the plugin reads/writes the localStorage key lte.sidebar.state, storing either "sidebar-open" or "sidebar-collapse".
Programmatic methods:
| Method | Description |
|---|---|
toggle() |
Expand or collapse based on current state (persists if enabled) |
expand() |
Expand the sidebar; fires open.lte.push-menu |
collapse() |
Collapse the sidebar; fires collapse.lte.push-menu |
isCollapsed() |
true if <body> has sidebar-collapse |
isExplicitlyOpen() |
true if <body> has sidebar-open (mobile, user-opened) |
isMiniMode() |
true if <body> has sidebar-mini |
isMobileSize() |
true if window.innerWidth ≤ sidebarBreakpoint |
saveSidebarState(state) |
Manually persist "sidebar-open" or "sidebar-collapse" |
loadSidebarState() |
Read and apply persisted state |
clearSidebarState() |
Remove persisted state |
updateStateByResponsiveLogic() |
Recompute state from viewport size (auto-called on resize) |
5.2 Treeview — sidebar submenus
Covered in detail in Section 4. Programmatic API:
import { Treeview } from "admin-lte"
const item = document.querySelector(".sidebar-menu .nav-item")
const tv = new Treeview(item, { accordion: true, animationSpeed: 300 })
tv.open() // expand this item's submenu
tv.close() // collapse it
tv.toggle() // toggle
5.3 CardWidget — collapsible / removable / maximizable cards
Adds collapse, remove, and maximize controls to any Bootstrap .card. Put the trigger buttons inside .card-tools in the card header:
<div class="card">
<div class="card-header">
<h3 class="card-title">Card Title</h3>
<div class="card-tools">
<button type="button" class="btn btn-tool" data-lte-toggle="card-collapse" title="Collapse">
<i data-lte-icon="expand" class="bi bi-plus-lg"></i>
<i data-lte-icon="collapse" class="bi bi-dash-lg"></i>
</button>
<button type="button" class="btn btn-tool" data-lte-toggle="card-maximize" title="Maximize">
<i class="bi bi-fullscreen"></i>
</button>
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove" title="Remove">
<i class="bi bi-x-lg"></i>
</button>
</div>
</div>
<div class="card-body">Card content here.</div>
<div class="card-footer">Card footer</div>
</div>
Programmatic methods: collapse(), expand(), toggle(), maximize(), minimize(), toggleMaximize(), remove(). Instantiate with an optional animationSpeed (default 500 ms):
import { CardWidget } from "admin-lte"
const widget = new CardWidget(document.querySelector("#chart-card"), { animationSpeed: 250 })
widget.maximize()
Note
Nested cards are handled correctly — collapsing a parent card does not affect child cards. Maximizing a card also adds
maximized-cardto<html>so global styles can react. A card that was collapsed before you maximize it remembers that state (tracked via thewas-collapsedclass).
5.4 DirectChat — chat contacts pane
Toggles a contacts pane inside a .direct-chat card. Add data-lte-toggle="chat-pane" to a button inside the chat card:
<div class="card direct-chat">
<div class="card-header">
<h3 class="card-title">Direct Chat</h3>
<div class="card-tools">
<button type="button" class="btn btn-tool" data-lte-toggle="chat-pane" title="Toggle Contacts">
<i class="bi bi-people-fill"></i>
</button>
</div>
</div>
<div class="card-body">
<div class="direct-chat-messages"><!-- messages --></div>
<div class="direct-chat-contacts"><!-- contacts --></div>
</div>
</div>
Programmatic: new DirectChat(element).toggle(). The constructor takes no config object — pass only the .direct-chat element. See the direct-chat recipe for a fuller example.
5.5 FullScreen — native browser fullscreen
Toggles the whole page into the browser's native fullscreen mode. Use data-lte-icon="maximize" and data-lte-icon="minimize" on the child icons so the right one shows:
<button type="button" class="btn" data-lte-toggle="fullscreen">
<i data-lte-icon="maximize" class="bi bi-arrows-fullscreen"></i>
<i data-lte-icon="minimize" class="bi bi-fullscreen-exit d-none"></i>
</button>
Programmatic: new FullScreen(button).toggleFullScreen().
Note
Fullscreen targets
<html>, so the entire page goes fullscreen. To make just one card fill the screen, use the CardWidgetmaximize()method instead. The plugin checksdocument.fullscreenEnabledbefore acting, and toggles the icons via Bootstrap's.d-noneutility so it works with any icon library (Bootstrap Icons, FontAwesome, Lucide, etc.).
5.6 Layout — transitions and load signal
This plugin self-initializes on <body> — there's nothing to wire up. It does two things automatically:
- Holds transitions during resize — adds
hold-transitionto<body>briefly so the sidebar/navbar/content don't animate awkwardly while the window is being resized. - Signals app-loaded — adds
app-loadedto<body>shortly afterDOMContentLoaded. Use this in CSS to defer entrance animations until the layout is ready:
/* Only animate after the app is loaded */
body.app-loaded .app-sidebar {
transition: width 0.3s ease;
}
The single public method, holdTransition(time), lets you suppress transitions around your own DOM changes:
import { Layout } from "admin-lte"
const layout = new Layout(document.body)
layout.holdTransition(200)
document.body.classList.toggle("sidebar-mini")
5.7 AccessibilityManager
AdminLTE auto-initializes a set of WCAG 2.1 AA features when it loads — you get them for free. They are configured in the bundle with everything enabled:
| Feature | WCAG criterion | What it does |
|---|---|---|
| Skip links | 2.4.1 | Adds "Skip to main content" / "Skip to navigation" links |
| Focus management | 2.4.3, 2.4.7 | Tab cycling, focus trapping in modals, focus restoration |
| Keyboard navigation | 2.1.1 | Arrow-key navigation in menus; Enter/Space for custom role="button" elements |
| Reduced motion | 2.3.3 | Respects the OS prefers-reduced-motion setting by disabling animations |
| Live announcements | 4.1.3 | Announces error and success messages to screen readers |
| Error identification | 3.3.1, 3.3.2 | Auto-labels unlabelled inputs; announces form-validation errors |
| Table accessibility | 1.3.1 | Adds scope attributes to table headers automatically |
If you need to control it, the helper initAccessibility() and the manager's public API are exported:
import { initAccessibility } from "admin-lte"
const a11y = initAccessibility({
announcements: true,
skipLinks: true,
focusManagement: true,
keyboardNavigation: true,
reducedMotion: true
})
a11y.announce("Item saved successfully", "polite") // screen-reader announcement
a11y.focusElement("#my-input") // move focus + scroll into view
a11y.trapFocus(document.querySelector(".my-dialog")) // trap Tab inside a container
a11y.addLandmarks() // add ARIA landmark roles
Set any feature flag to false to disable it.
Tip
A standalone
accessibilityUtilsobject is also exported, withcheckColorContrast(fg, bg)(returns{ ratio, passes }against the 4.5:1 threshold),isFocusable(element), andgenerateId(prefix)helpers for building accessible UI of your own.
6. Color Modes (Light / Dark / Auto)
AdminLTE follows Bootstrap 5.3's native theming. The active theme is set by the data-bs-theme attribute — apply it to <html>, <body>, or any single element:
<!-- Whole page dark -->
<html data-bs-theme="dark">
<!-- Just the sidebar dark, page light (the demo look) -->
<aside class="app-sidebar" data-bs-theme="dark">…</aside>
A working light/dark/auto toggle
AdminLTE's demos include a dropdown toggle in the topbar that switches the attribute and remembers the choice. The markup uses data-bs-theme-value on each option:
<li class="nav-item dropdown">
<button class="btn btn-link nav-link dropdown-toggle d-flex align-items-center"
id="bd-theme" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<span class="theme-icon-active"><i class="my-1"></i></span>
<span class="d-lg-none ms-2" id="bd-theme-text">Toggle theme</span>
</button>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="bd-theme-text">
<li><button type="button" class="dropdown-item d-flex align-items-center active" data-bs-theme-value="light">
<i class="bi bi-sun-fill me-2"></i> Light <i class="bi bi-check-lg ms-auto d-none"></i></button></li>
<li><button type="button" class="dropdown-item d-flex align-items-center" data-bs-theme-value="dark">
<i class="bi bi-moon-fill me-2"></i> Dark <i class="bi bi-check-lg ms-auto d-none"></i></button></li>
<li><button type="button" class="dropdown-item d-flex align-items-center" data-bs-theme-value="auto">
<i class="bi bi-circle-half me-2"></i> Auto <i class="bi bi-check-lg ms-auto d-none"></i></button></li>
</ul>
</li>
The accompanying script reads the preferred theme (stored choice → OS preference), writes data-bs-theme on <html>, and persists the user's selection to localStorage:
(() => {
"use strict";
const storedTheme = localStorage.getItem("theme");
const getPreferredTheme = () =>
storedTheme ||
(window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");
const setTheme = (theme) => {
if (theme === "auto" && window.matchMedia("(prefers-color-scheme: dark)").matches) {
document.documentElement.setAttribute("data-bs-theme", "dark");
} else {
document.documentElement.setAttribute("data-bs-theme", theme);
}
};
setTheme(getPreferredTheme());
window.addEventListener("DOMContentLoaded", () => {
for (const toggle of document.querySelectorAll("[data-bs-theme-value]")) {
toggle.addEventListener("click", () => {
const theme = toggle.getAttribute("data-bs-theme-value");
localStorage.setItem("theme", theme);
setTheme(theme);
});
}
});
})();
Note
This color-mode toggle is a copy-paste snippet, not part of the
adminlte.jsbundle. The snippet persists the choice under the localStorage keytheme. If you write your own toggle, make sure it both setsdata-bs-themeand writes to localStorage.
Tip
The Auto option follows the OS preference live: the script listens for changes to
prefers-color-schemeand re-applies the theme when the user switches their system between light and dark.
7. Customizing the Look
You can retheme AdminLTE two ways:
- CSS custom properties — quick, no build step, works on the prebuilt CSS.
- SCSS variables — requires a build, but lets you change anything, including breakpoints and sidebar width.
Quick wins with CSS variables
Bootstrap and AdminLTE expose dozens of custom properties on :root. Override them in your own stylesheet — no rebuild needed:
:root,
[data-bs-theme="light"] {
--bs-primary: #6610f2; /* swap Bootstrap blue for purple */
--bs-primary-rgb: 102, 16, 242;
--bs-body-bg: #f3f4f6;
}
[data-bs-theme="dark"] {
--bs-body-bg: #14171c;
--bs-body-color: #e9ecef;
}
Most of AdminLTE's chrome is built on var(--bs-primary), so it picks this up automatically.
| Variable | Default | Controls |
|---|---|---|
--bs-primary |
#0d6efd |
Brand color; active sidebar items, primary buttons |
--bs-body-bg |
#fff / #212529 (dark) |
Page background |
--bs-body-color |
#212529 |
Default text color |
--bs-border-color |
#dee2e6 |
Hairline borders |
--bs-border-radius |
.375rem |
Default radius for cards, buttons, inputs |
--bs-font-sans-serif |
system-ui, … |
Default font stack |
SCSS variables (build from source)
When building from source, override variables before importing AdminLTE. All AdminLTE/Bootstrap variables use !default, so the first declaration wins:
// my-theme.scss
// 1. Your overrides FIRST
$primary: #6610f2;
$lte-sidebar-width: 280px;
$border-radius: .25rem;
// 2. Then import AdminLTE (which imports Bootstrap)
@import "node_modules/admin-lte/src/scss/adminlte";
The most-overridden AdminLTE variables and their defaults:
// Sidebar
$lte-sidebar-width: 250px; // collapses to a ~70px mini state
$lte-sidebar-breakpoint: lg; // breakpoint where the sidebar goes off-canvas
$lte-sidebar-padding-x: .5rem;
$lte-sidebar-padding-y: .5rem;
// Transitions
$lte-transition-speed: .3s;
$lte-transition-fn: ease-in-out;
Important
Sidebar width and breakpoints are SCSS-only — there are no CSS custom properties for them. If you need to change those, you must build from source. Use CSS variables for everything they cover (colors, radius, fonts), because those survive AdminLTE upgrades without merge conflicts.
When to use which
| Customization | CSS variables | SCSS rebuild |
|---|---|---|
| Brand colors | ✅ | ✅ |
| Body / text colors | ✅ | ✅ |
| Border radius | ✅ | ✅ |
| Sidebar width | ❌ | ✅ |
| Breakpoint changes | ❌ | ✅ |
| Spacing scale | ❌ | ✅ |
Sidebar branding
.sidebar-brand accepts text, an image, or both:
<div class="sidebar-brand">
<a href="/" class="brand-link">
<img src="/assets/logo.svg" alt="Logo" class="brand-image opacity-75 shadow" />
<span class="brand-text fw-light">My Dashboard</span>
</a>
</div>
Compact mode
Add .compact-mode to .app-wrapper (or higher) to tighten padding across the whole layout — handy for data-dense dashboards:
<div class="app-wrapper compact-mode">…</div>
8. Common Recipes
Copy-paste patterns that show up in every admin dashboard. Each assumes you have a working AdminLTE page from Quick Start.
A KPI card (small-box)
The bright stat boxes at the top of most dashboards. Swap text-bg-primary for text-bg-success, text-bg-warning, text-bg-danger, etc.
<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 with other values + colors -->
</div>
A page-title + breadcrumb row
The standard .app-content-header pattern:
<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 active" aria-current="page">Current page</li>
</ol>
</div>
</div>
</div>
</div>
A user dropdown in the topbar
Put this inside <ul class="navbar-nav ms-auto"> in .app-header:
<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>
A responsive data table
Wrap the table in .table-responsive so it scrolls horizontally on narrow screens 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></tr>
</thead>
<tbody><!-- rows --></tbody>
</table>
</div>
</div>
</div>
For sorting/filtering/pagination, use Tabulator.
A direct-chat widget
<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>
<div class="direct-chat-contacts"><!-- contacts, shown when toggled --></div>
</div>
</div>
Highlighting the active sidebar item from JavaScript
For a single rendered sidebar with client-side route highlighting:
function setActiveSidebarItem(href) {
document.querySelectorAll(".sidebar-menu .nav-link").forEach((el) => {
el.classList.toggle("active", el.getAttribute("href") === href)
})
}
setActiveSidebarItem(window.location.pathname) // call on every route change
Refitting a chart when the sidebar collapses
Charts read their container width on init, so re-measure them after the sidebar transition finishes:
document.addEventListener("collapse.lte.push-menu", () => {
setTimeout(() => chart.updateOptions({}), 350) // ~300ms transition + buffer
})
document.addEventListener("open.lte.push-menu", () => {
setTimeout(() => chart.updateOptions({}), 350)
})
The same pattern works for Tabulator, FullCalendar, and any width-sensitive widget.
9. Adding Third-Party Widgets
AdminLTE deliberately ships a lean dependency tree — it doesn't bundle date pickers, charts, or rich-text editors. Instead, drop in best-in-class third-party libraries when you need them. Every library below is MIT-licensed, actively maintained, and jQuery-free.
| Need | Library | One-line wire-up |
|---|---|---|
| Date / time picker | Flatpickr | flatpickr("#datepicker", { dateFormat: "Y-m-d" }) |
| Multi-select / tags | Tom Select | new TomSelect("#tags", { plugins: ["remove_button"] }) |
| Range slider | noUiSlider | noUiSlider.create(el, { start: [20, 80], range: { min: 0, max: 100 } }) |
| Color picker | Pickr | Pickr.create({ el: "#color-picker", theme: "classic" }) |
| Input mask | IMask | IMask(el, { mask: "(000) 000-0000" }) |
| File upload | Dropzone / FilePond | new Dropzone("#uploader", { maxFilesize: 5 }) |
| Rich text | Quill | new Quill("#editor", { theme: "snow" }) |
| Markdown | EasyMDE | new EasyMDE({ element: el }) |
| Charts | ApexCharts / Chart.js | new ApexCharts(el, options).render() |
| Data tables | Tabulator | new Tabulator("#table", { layout: "fitColumns" }) |
| Calendar | FullCalendar | new FullCalendar.Calendar(el, { initialView: "dayGridMonth" }).render() |
| Drag & drop | SortableJS | new Sortable(el, { animation: 150 }) |
| Lightbox | GLightbox | GLightbox() |
The v4 demo pages already use several of these: ApexCharts (dashboard), Tabulator (tables/data), FullCalendar (pages/calendar), and SortableJS (pages/kanban). Each library ships a Bootstrap 5 theme where relevant (Tom Select, Tabulator), so it matches AdminLTE's form controls.
Icon libraries
AdminLTE ships Bootstrap Icons by default (~1,900 SVG glyphs, MIT). All of these coexist with AdminLTE if you want more — just load the font and change the <i> classes:
| Library | Icons | Notes |
|---|---|---|
| Bootstrap Icons | 1,900+ | Default, SVG, MIT |
| Lucide | 1,500+ | ISC, very consistent style |
| Tabler Icons | 5,800+ | MIT, broadest free set |
| Material Symbols | 3,500+ | Apache 2.0, variable font |
| FontAwesome Free | 2,000+ | Font-based |
| Phosphor | 6,000+ | MIT, six weights |
Tip
For production, prefer npm + a bundler (for tree-shaking and version locking) or self-hosting the minified files over relying on a public CDN long-term. Pin a specific version in any CDN URL so snippets stay reproducible.
10. Right-to-Left (RTL) Layouts
AdminLTE ships a pre-built RTL stylesheet for Arabic, Hebrew, Persian, Urdu, and other right-to-left scripts. Every release publishes RTL variants of every CSS file:
dist/css/adminlte.css ← LTR (default)
dist/css/adminlte.rtl.css ← RTL
dist/css/adminlte.min.css
dist/css/adminlte.rtl.min.css
To switch a page to RTL, load the .rtl stylesheet and set dir="rtl" on <html>:
<html lang="ar" dir="rtl">
<head>
<link rel="stylesheet" href="dist/css/adminlte.rtl.min.css" />
</head>
<body class="layout-fixed sidebar-expand-lg bg-body-tertiary">
<!-- same markup as LTR -->
</body>
</html>
That's all — the sidebar docks to the right, scrollbars flip, and Bootstrap's .ms-* / .float-start utilities mirror automatically (setting dir="rtl" triggers Bootstrap 5.3's logical-property pathway). For a mixed-language page, scope dir="rtl" to a single subtree instead of swapping the whole stylesheet.
| Flips automatically | Does not flip |
|---|---|
margin-left / padding-left → right |
Directional icons (bi-arrow-right etc.) — swap manually |
left / right positioning |
Inline images, charts, third-party widgets (check each for an RTL option) |
text-align: left / right |
Numbers (digits stay LTR — standard Unicode behavior) |
| Sidebar position; dropdown open direction |
Caution
The minified RTL build is named
adminlte.rtl.min.css, notadminlte.min.rtl.css— filename order matters. And don't load both LTR and RTL stylesheets on the same page; pick one.
11. Upgrading from AdminLTE 3
AdminLTE 4 is a ground-up rewrite on Bootstrap 5.3 with no jQuery. If you're upgrading a v3 project, these are the changes most likely to bite.
| AdminLTE 3 | AdminLTE 4 | |
|---|---|---|
| CSS framework | Bootstrap 4.6 | Bootstrap 5.3 |
| JavaScript | jQuery + vanilla | Vanilla TypeScript only |
| Dark mode | .dark-mode body class |
data-bs-theme attribute |
| RTL | Separate build | Auto-generated via rtlcss |
| Browsers | IE 11 forks available | Modern evergreen only |
| Icons | FontAwesome | Bootstrap Icons |
Class renames (the bulk of the work)
| AdminLTE 3 | AdminLTE 4 |
|---|---|
.wrapper |
.app-wrapper |
.main-header |
.app-header |
.main-sidebar |
.app-sidebar |
.content-wrapper |
.app-main |
.main-footer |
.app-footer |
.content-header |
.app-content-header |
.content |
.app-content |
data-widget="pushmenu" |
data-lte-toggle="sidebar" |
data-widget="treeview" |
data-lte-toggle="treeview" |
data-widget="card-widget" |
data-lte-toggle="card-collapse" / card-remove / card-maximize |
data-widget="fullscreen" |
data-lte-toggle="fullscreen" |
.dark-mode (on <body>) |
data-bs-theme="dark" |
You'll also need the Bootstrap 4→5 utility renames (data-toggle → data-bs-toggle, .ml-*/.mr-* → .ms-*/.me-*, .float-left/.float-right → .float-start/.float-end, .font-weight-* → .fw-*, etc.) — these come from Bootstrap, not AdminLTE, and a regex find-replace handles most of them.
jQuery removal
AdminLTE 3 plugin calls like $('.sidebar').PushMenu() no longer exist. Either use the data API (which does it for you), or import the plugin class:
import { PushMenu } from "admin-lte"
new PushMenu(document.querySelector(".sidebar-toggle"), {}).toggle()
Suggested order
- Branch first — keep
masteron v3 until v4 is stable. - Run the class-rename find-replace pass.
- Update
data-toggle→data-bs-toggleacross all templates. - Replace
.dark-modetoggle code withdata-bs-themewrites. - Audit jQuery calls — remove them or import plugin classes.
- Re-test responsive breakpoints (Bootstrap 5 adds
xxl).
See the project's full Migration from v3 guide for the complete list.
12. Troubleshooting
Error: the sidebar doesn't collapse when I click the hamburger
Cause: PushMenu isn't loaded, or the trigger uses the v3 attribute.
Solution: Confirm adminlte.js (or adminlte.min.js) is on the page and after the markup it operates on. Verify your hamburger button uses data-lte-toggle="sidebar" — not the v3 data-widget="pushmenu".
Prevention: Keep the script tags at the end of <body> in the order shown in Quick Start.
Error: dark mode doesn't persist after refresh
Cause: Your toggle isn't writing to localStorage, or isn't reading it on load.
Solution: Use the Color Mode toggle snippet, which persists under the localStorage key theme. A custom toggle must both call document.documentElement.setAttribute('data-bs-theme', …) and write the choice to localStorage on change.
Error: pressing Escape closes a Bootstrap modal and the sidebar
Cause: A pre-release (RC) build. Solution: Update to the latest 4.0.0 — this was fixed (issue #5993). AdminLTE's accessibility module now defers Escape handling inside open modals to Bootstrap.
Error: my custom SCSS doesn't override AdminLTE's defaults
Cause: Your overrides come after AdminLTE's @import.
Solution: Put your variable overrides before the import. AdminLTE variables use !default, so the first declaration wins (see Section 7).
Error: npm install fails with peer dependency errors
Cause: An npm older than 8.3, which ignores the overrides block in package.json.
Solution: Upgrade to npm 8.3+ (which respects overrides), or install with --legacy-peer-deps as a fallback.
Error: Web Font CORS error loading FontAwesome all.min.css
Cause: Loading an icon font cross-origin without proper CORS headers (reported in issue #6008).
Solution: AdminLTE 4 standardizes on Bootstrap Icons, which is SVG-based and avoids the web-font CORS class of problems. If you bring your own FontAwesome, self-host it or use a CDN that serves the correct Access-Control-Allow-Origin headers for font files.
Error: the fullscreen button shifts the icon's position
Cause: A pre-4.0.0 build that toggled inline display on the icon.
Solution: Update to 4.0.0 — the FullScreen plugin now toggles Bootstrap's .d-none utility instead (issue #6021), which works with any icon library.
Error: content lands flush against the screen edge
Cause: Missing .container-fluid inside .app-content.
Solution: Wrap your content in <div class="container-fluid"> (or .container for capped width).
13. FAQ
Q: What is AdminLTE, exactly? A free, MIT-licensed admin dashboard template — HTML, CSS, and JavaScript built on Bootstrap 5.3. It is not a framework or an npm component library. You drop it into your project, edit the markup to suit your app, and ship.
Q: Do I need a build step to use it? No. The CDN-only approach in Quick Start needs no install or build. The npm workflow is there if you want to customize SCSS variables or tree-shake the JavaScript.
Q: Which Bootstrap version does v4 require?
Bootstrap 5.3.x (the current package.json pins 5.3.8). Bootstrap 5.0/5.1/5.2 will not work — the color-mode and data-bs-theme system landed in 5.3.
Q: Can I use AdminLTE 4 with jQuery?
You don't need it — AdminLTE 4's JavaScript is vanilla. If your app already uses jQuery, the two coexist fine, but none of AdminLTE's plugins call into it and there are no $.fn.xxx() shims.
Q: Can I use it with WordPress / Laravel / Symfony / Django / Rails? Yes — it's server-rendered HTML. Copy the demo pages into your views/templates, replace static content with your framework's template variables, and wire up routes and auth as usual. Community Composer packages exist for Laravel and Symfony, but they often lag upstream — verify they ship v4 before depending on them.
Q: React / Vue / Svelte / Angular? Workable but less natural — AdminLTE's plugins use DOM lifecycle hooks that fight SPA reconciliation. The recommended approach is to use AdminLTE for its CSS and write your own framework components for the interactive parts, or pick a component library built for your framework.
Q: How do I change the primary color?
Override --bs-primary (and --bs-primary-rgb) on :root — no rebuild needed. See Customizing the Look.
Q: Can I use FontAwesome instead of Bootstrap Icons?
Yes. Nothing in AdminLTE requires Bootstrap Icons. Load FontAwesome's stylesheet and replace <i class="bi bi-x"> with <i class="fas fa-x">.
Q: Is AdminLTE free for commercial use?
Yes — MIT licensed. Use it in commercial products, SaaS apps, client work, anything. The only requirement is preserving the copyright notice in the source files (adminlte.css / adminlte.js). No UI attribution is required.
Q: Can I sell a product made with AdminLTE? Yes — the MIT license explicitly permits it, including reselling modified versions of AdminLTE itself, as long as you keep the original copyright notice.
Q: How do I get notified of new versions?
Watch the GitHub repo in Releases-only mode, or subscribe to the RSS feed at https://github.com/ColorlibHQ/AdminLTE/releases.atom.
14. Reference
Plugin data-API attributes
| Attribute | Plugin | Goes on |
|---|---|---|
data-lte-toggle="sidebar" |
PushMenu | A button/link in the header |
data-lte-toggle="treeview" |
Treeview | The parent <ul class="sidebar-menu"> |
data-lte-toggle="card-collapse" |
CardWidget | A button in .card-tools |
data-lte-toggle="card-remove" |
CardWidget | A button in .card-tools |
data-lte-toggle="card-maximize" |
CardWidget | A button in .card-tools |
data-lte-toggle="chat-pane" |
DirectChat | A button in a .direct-chat card |
data-lte-toggle="fullscreen" |
FullScreen | Any button |
data-lte-icon="maximize" / "minimize" |
FullScreen | Icons inside the fullscreen button |
data-lte-icon="expand" / "collapse" |
CardWidget | Icons inside the collapse button |
Plugin config attributes
| Attribute | Default | Plugin | Goes on |
|---|---|---|---|
data-sidebar-breakpoint |
992 |
PushMenu | .app-sidebar |
data-enable-persistence |
false |
PushMenu | .app-sidebar |
data-accordion |
true |
Treeview | the parent <ul> |
data-animation-speed |
300 |
Treeview | the parent <ul> |
CSS classes the plugins set
| Class | Set by | On | Meaning |
|---|---|---|---|
sidebar-collapse |
PushMenu | <body> |
Sidebar collapsed |
sidebar-open |
PushMenu | <body> |
Mobile sidebar explicitly open |
sidebar-mini |
PushMenu | <body> |
Mini-sidebar mode |
menu-open |
Treeview | .nav-item |
Submenu expanded |
collapsed-card |
CardWidget | .card |
Card body collapsed |
maximized-card |
CardWidget | <html> + .card |
Card maximized |
direct-chat-contacts-open |
DirectChat | .direct-chat |
Contacts pane visible |
hold-transition |
Layout | <body> |
Transitions briefly disabled |
app-loaded |
Layout | <body> |
Initial load animation finished |
reduce-motion |
AccessibilityManager | <body> |
OS prefers-reduced-motion detected |
npm scripts (when building from source)
| Command | What it does |
|---|---|
npm start / npm run dev |
Dev server with file watching at http://localhost:3000 |
npm run build |
Build all assets (clean + compile) |
npm run production |
Full production build with linting + bundlewatch |
npm run css |
Build CSS only (compile → prefix → RTL → minify) |
npm run js |
Build JavaScript only (compile → minify) |
npm run lint |
Run all linters (JS, CSS, docs, lockfile) |
Runtime dependencies (loaded alongside AdminLTE)
| Dependency | Version (pinned) | Why |
|---|---|---|
| Bootstrap | 5.3.8 | The underlying component framework |
| Popper | 2.11.8 | Bootstrap dropdowns / tooltips / popovers |
| Bootstrap Icons | 1.13.1 | Default icon set |
| OverlayScrollbars | 2.11.0 | The sidebar's custom scrollbar |
Browser support
AdminLTE 4 supports the same range as Bootstrap 5 — the latest stable releases of all major browsers. From the project's .browserslistrc: Chrome >= 60, Firefox >= 60, iOS >= 12, Safari >= 12, not Explorer <= 11.