Menu System
The sidebar (and optional top-nav) menu is defined as an array under the menu
key in config/adminlte.php. Each element of the array is a single menu
item described by an associative array. Items pass through a filter pipeline
before they are rendered by resources/views/partials/menu-item.blade.php.
- Config:
config/adminlte.php('menu'array,'filters'array) - Builder:
src/AdminLte.php - Helpers:
src/Menu/MenuItemHelper.php - Filters:
src/Menu/Filters/*.php - View:
resources/views/partials/menu-item.blade.php
Item Types
Section Header
A non-clickable label that groups items. Rendered as <li class="nav-header">.
['header' => 'PAGES'],
| Key | Required | Description |
|---|---|---|
header |
yes | The uppercase section label text. |
MenuItemHelper::isHeader() returns true when an item has a header key.
Link
A standard navigation link. Requires text plus a destination (url or
route).
[
'text' => 'Dashboard',
'url' => '/',
'icon' => 'bi bi-speedometer',
],
| Key | Required | Description |
|---|---|---|
text |
yes | The link label. |
url |
one of | Raw URL (relative or absolute). |
route |
one of | Named route. String, or [name, params] array. |
icon |
no | Bootstrap Icons class (e.g. bi bi-speedometer). Defaults to bi bi-circle if omitted. |
icon_color |
no | Color suffix → renders text-{color} on the icon. |
label |
no | Badge value shown after the text. |
label_color |
no | Badge color (text-bg-{color}). Defaults to primary. |
target |
no | Anchor target (e.g. _blank). Adds rel="noopener" automatically. |
can |
no | Gate ability (string or array) required to display the item. |
can_params |
no | Model/argument passed to the gate check. |
active |
no | URL pattern(s) (string or array) that mark the item active. |
MenuItemHelper::isLink() returns true for any item with text that is not a
search box.
Treeview / Submenu
An item with a submenu array becomes a collapsible treeview. Submenus can be
nested to any depth — the menu-item view includes itself recursively.
[
'text' => 'Widgets',
'icon' => 'bi bi-box-seam-fill',
'submenu' => [
['text' => 'Small Box', 'url' => 'demo/widgets/small-box', 'icon' => 'bi bi-circle'],
['text' => 'Info Box', 'url' => 'demo/widgets/info-box', 'icon' => 'bi bi-circle'],
[
'text' => 'Nested',
'icon' => 'bi bi-circle',
'submenu' => [
['text' => 'Deep Item', 'url' => '#', 'icon' => 'bi bi-record-circle-fill'],
],
],
],
],
| Key | Required | Description |
|---|---|---|
text |
yes | The parent label. |
icon |
no | Icon for the parent item. |
submenu |
yes | Array of child items (any of the item types, including more submenus). |
A treeview parent uses href="#"; the route/url keys are not needed on it.
MenuItemHelper::isSubmenu() returns true when submenu is an array. A parent
is automatically expanded (menu-open) and marked active when any descendant
is active.
Search Box
A navbar search input, identified by type => 'navbar-search'.
[
'type' => 'navbar-search',
'method' => 'get', // normalized default
'placeholder' => 'Search', // normalized default
'url' => 'search', // normalized default '#'
'topnav_right' => true,
],
SearchFilter fills in method (get), placeholder (Search), and url
(#) when they are omitted.
Badges & Icon Colors
Both link and treeview items support a badge and a colored icon.
['text' => 'Inbox', 'url' => 'admin/mailbox', 'icon' => 'bi bi-envelope', 'label' => 12, 'label_color' => 'danger'],
['text' => 'Important', 'url' => '#', 'icon' => 'bi bi-circle', 'icon_color' => 'danger'],
labelrenders a badge:<span class="nav-badge badge text-bg-{label_color}">.label_colordefaults toprimaryif omitted.icon_coloraddstext-{icon_color}to the<i class="nav-icon ...">.
URL vs Route Resolution (HrefFilter)
HrefFilter computes the final href for each item (and recurses into
submenus). Resolution order:
- If
hrefis already set, it is kept as-is. - Headers and
navbar-searchitems get nohref. route→ resolved with Laravel'sroute()helper.- String form:
route($item['route']). - Array form:
route($item['route'][0], $item['route'][1] ?? [])for params.
- String form:
url→ external URLs (matching//,mailto:,tel:) are used verbatim; otherwise passed throughurl().- If none of the above,
hreffalls back to'#'.
['text' => 'Users', 'route' => 'users.index'], // route('users.index')
['text' => 'Edit', 'route' => ['users.edit', ['id' => 1]]], // route with params
['text' => 'Docs', 'url' => 'https://example.com', 'target' => '_blank'], // external, kept as-is
['text' => 'Local', 'url' => 'admin/users'], // url('admin/users')
Active-State Marking (ActiveFilter)
ActiveFilter decides whether an item is highlighted as the current page:
- If
activeis already a boolean, it is respected as-is. - If
activeis a pattern (or list of patterns), the item is active when the current request matches any pattern viaRequest::is(). - If no
activepattern is given, one is auto-derived fromurl: for a URLadmin/usersit matches bothadmin/usersandadmin/users/*. Aurlof'/'matches only the site root;'#'is never auto-matched. - A submenu parent becomes active if any child is active (recursively).
// Explicit patterns:
['text' => 'Users', 'url' => 'admin/users', 'active' => ['admin/users*', 'admin/people*']],
In the view, an active item gets the active class; an active treeview parent
also gets menu-open so it renders expanded.
Gate Filtering (GateFilter)
GateFilter removes items the current user is not authorized to see:
- Only items with a
cankey are checked; others pass through untouched. canmay be a single ability string or an array of abilities. The item is shown if the user passes any of them (Gate::allows).can_paramsis forwarded to the gate as the model/argument.- Returning
nullfrom the filter drops the item from the menu entirely.
['text' => 'Admin Panel', 'url' => 'admin', 'can' => 'access-admin'],
['text' => 'Edit Post', 'route' => 'posts.edit', 'can' => 'update', 'can_params' => $post],
The Filter Pipeline
Filters are listed in config('adminlte.filters') and run in array order by
AdminLte::buildFiltered(). Each filter implements FilterInterface with a
single method:
public function transform(array $item): ?array;
It returns the (possibly modified) item, or null to remove it entirely. The
default pipeline order is:
| Order | Filter | Effect |
|---|---|---|
| 1 | GateFilter |
Drops unauthorized items (can). |
| 2 | HrefFilter |
Resolves href from route / url. |
| 3 | ActiveFilter |
Marks the active item / treeview branch. |
| 4 | SearchFilter |
Normalizes navbar-search items. |
The result is cached on the AdminLte instance for the request. Add custom
filters by appending your own FilterInterface class to the filters array.
Scoped Menus
AdminLte is registered as a singleton; resolve it via app('adminlte'). The
menu() method returns the filtered menu for a given scope:
app('adminlte')->menu('sidebar'); // items not flagged topnav-only
app('adminlte')->menu('navbar-left'); // items with 'topnav' => true
app('adminlte')->menu('navbar-right'); // items with 'topnav_right' => true
app('adminlte')->menu(); // the full filtered list
Scope rules (see MenuItemHelper):
- sidebar: items where both
topnavandtopnav_rightare empty. - navbar-left: items with a truthy
topnavkey. - navbar-right: items with a truthy
topnav_rightkey.
// Place an item in the right side of the top navbar instead of the sidebar:
['text' => 'Help', 'url' => 'help', 'icon' => 'bi bi-question-circle', 'topnav_right' => true],
Runtime Additions (addAfter)
Items can be appended at runtime (e.g. from a service provider's boot()),
which is useful for package- or permission-driven menus:
app('adminlte')->addAfter('some-key',
['header' => 'REPORTS'],
['text' => 'Sales', 'route' => 'reports.sales', 'icon' => 'bi bi-graph-up'],
);
Note: the current implementation appends the given items to the end of the menu and clears the cached filtered list so the additions are picked up on the next
menu()call. The$itemKeyargument is accepted for forward compatibility but items are not yet spliced relative to it.
Because the menu builder is a singleton, runtime additions persist for the rest of the request and reset on the next request.
Realistic Example
'menu' => [
// Section header
['header' => 'MAIN'],
// Simple link
[
'text' => 'Dashboard',
'route' => 'dashboard',
'icon' => 'bi bi-speedometer',
],
// Treeview with a badge on the parent and an authorization gate
[
'text' => 'Shop',
'icon' => 'bi bi-bag',
'label' => 3,
'label_color' => 'danger',
'can' => 'manage-shop',
'submenu' => [
['text' => 'Orders', 'route' => 'orders.index', 'icon' => 'bi bi-circle'],
['text' => 'Products', 'route' => 'products.index', 'icon' => 'bi bi-circle'],
],
],
['header' => 'OTHER'],
// External link opening in a new tab
[
'text' => 'Documentation',
'url' => 'https://adminlte.io/docs',
'icon' => 'bi bi-book',
'target' => '_blank',
],
// Colored-icon link
[
'text' => 'Important',
'url' => '#',
'icon' => 'bi bi-exclamation-triangle',
'icon_color' => 'warning',
],
],