Skip to content

Menu Configuration ​

In this section we'll explain how to configure the menu items that will be available on your admin panel.

Static Menu Config ​

You can specify (in a static way) the set of menu items to display in the left sidebar and/or the top navbar. A menu item representing a link should have a text attribute and an url (or route) attribute. Also, and optionally, you can use the icon attribute to specify an icon for every menu item (Bootstrap Icons by default). A single string instead of an array represents a header in the sidebar, a header is used to group items under a label. However, a header may also be represented by an array containing the header attribute. There is also a can attribute that may be used as a filter with the Laravel's built in Gate functionality. Even more, you can create a nested menu using the submenu attribute. Also, there are other options and attributes available that will be explained later.

Here is a basic example that will give you a quick overview of a menu configuration:

php
'menu' => [
    'MAIN NAVIGATION',
    [
        'text' => 'Blog',
        'url' => 'admin/blog',
    ],
    [
        'text' => 'Pages',
        'url' => 'admin/pages',
        'icon' => 'bi bi-file-earmark',
    ],
    [
        'text' => 'Show my website',
        'url' => '/',
        'target' => '_blank',
    ],
    [
        'header' => 'ACCOUNT SETTINGS',
    ],
    [
        'text' => 'Profile',
        'route' => 'admin.profile',
        'icon' => 'bi bi-person',
    ],
    [
        'text' => 'Change Password',
        'route' => 'admin.password',
        'icon' => 'bi bi-lock',
    ],
],

On the next table, we give a summary of the available attributes for the menu items. Take in consideration that most of these attributes are optional and will be explained later with more details.

AttributeDescription
activeTo define when the item should have the active style.
canPermissions of the item for use with Laravel's Gate.
classesTo add custom classes to a menu item.
dataAn array with data-* attributes for the item.
headerText representing the name of a header (only for headers).
iconAn icon for the item (Bootstrap Icons by default).
icon_colorAn AdminLTE color for the icon (info, primary, etc).
idTo define an id for the menu item.
keyAn unique identifier key for reference the item.
labelText for a badge associated with the item.
label_colorAn AdminLTE color for the badge (info, primary, etc).
modelA model class name or instance, used as the argument of the can checks.
routeA route name, usually used on link items.
shift[Deprecated] Classes to append to the list item (for shifting submenu items)
submenuArray with child items that enables nested menus definition.
targetThe underlying target attribute for link items.
textText representing the name of the item.
topnavBool to place the item on the top navbar.
topnav_rightBool to place the item in the right section of top navbar.
topnav_userBool to place the item in the user menu.
urlAn URL path, normally used on link items.

Now, we're going to review all of these attributes with more detail:

The active Attribute: ​

By default, a menu item is considered active if any of the following conditions holds:

  • The current path exactly matches the url attribute.
  • The current path without the query parameters matches the url attribute.
  • If it has a submenu containing an active menu item.

In order to override this default behavior, you can specify an active attribute containing an array with one or multiple URLs that will be used to search for a match. Even more, you can use asterisks and regular expressions on these URLs definitions in order to support some particular cases. To utilize a regex, you need to prefix your pattern with the regex: token and it will get evaluated automatically. The regex pattern will attempt to match the path of the URL returned by request()->path(), which returns the current URL without the domain name. At next, we can see an example that uses multiple URL definitions for the active state:

php
[
    'text' => 'Pages',
    'url' => 'pages',
    'active' => ['pages', 'content', 'content*', 'regex:@^content/[0-9]+$@']
]

In the previous case, the menu item will be considered active for all the next URLs:

  • http://my.domain.com/pages
  • http://my.domain.com/content
  • http://my.domain.com/content-user (because content*)
  • http://my.domain.com/content/1234 (because regex:@^content/[0-9]+$@)

The can Attribute: ​

You may use the can attribute if you want to conditionally show a menu item. This integrates with the Laravel's Gate functionality. If you need to conditionally show a header item, you need to wrap it in an array using the header attribute. You can also use multiple conditions entries with an array, check the next example for details:

php
[
    [
        'header' => 'BLOG',
        'can' => 'manage-blog',
    ],
    [
        'text' => 'Add new post',
        'url' => 'admin/blog/new',
        'can' => ['add-blog-post', 'other-right'],
    ],
]

So, for the previous example the header will show only if the user has the manage-blog permission, and the link will show if the user has the add-blog-post or the other-right permissions.

The classes Attribute: ​

This attribute provides a way to add custom classes to a particular menu item. The value should be a string with one or multiple class names, similar to the HTML class attribute. For example, you can make a colorful HEADER item centered on the left sidebar with the next definition:

php
[
    'header' => 'account_settings',
    'classes' => 'text-warning fw-bold text-center',
]

Or you can highlight an important link item with something like this:

php
[
    'text' => 'Important Link',
    'url' => 'important/link',
    'icon' => 'bi bi-exclamation-triangle',
    'classes' => 'text-danger text-uppercase',
]

NOTE

Use the Bootstrap 5.3 utility class names here. The Bootstrap 4 helpers that were valid on AdminLTE v3 were renamed: text-bold is now fw-bold, text-left / text-right are now text-start / text-end, ml-* / mr-* are now ms-* / me-*, and so on.

The data Attribute: ​

In order to add data-* attributes to your menu items, you can simply add an associative array called data to the item. Here is a basic example:

php
[
    'text' => 'New post',
    'url' => 'admin/blog/new',
    'data' => [
        'test-one' => 'content-one',
        'test-two' => 'content-two',
    ],
]

Then, the previous menu item will be rendered as this:

html
<a class="nav-link" href="http://<domain>/admin/blog/new"
   data-test-one="content-one"
   data-test-two="content-two">
    <i class="nav-icon bi bi-circle"></i>
    <p>New post</p>
</a>

The header Attribute: ​

This attribute is exclusive for header items, and the value is just his descriptive text. Headers are only available for the left sidebar and they provide a way to group items under a label. Example:

php
[
    'header' => 'REPORTS',
]

A header item can also be represented with a single string, for example "REPORTS", but the array format provides a way to combine it with other attributes, like the can one. The header attribute supports translations, as explained on the Translations section.

The icon and icon_color Attributes: ​

The icon attribute is optional, and the sidebar items will fall back to an open circle (bi bi-circle) if you leave it out. AdminLTE v4 ships Bootstrap Icons, so the available icons that you can use are those from that set. Just specify the class name of the icon and it will appear in front of your menu item. The icon_color attribute provides a way to setup an AdminLTE color for the icon (it is rendered as a text-{color} class). Example:

php
[
    'text' => 'profile',
    'url' => 'user/profile',
    'icon' => 'bi bi-person',
    'icon_color' => 'primary',
]

NOTE

The value of the icon attribute is copied verbatim into the class attribute of an <i> element, so you are free to use a different icon font. If you want to keep using, for example, Font Awesome, just load its stylesheet on your layout and write 'icon' => 'fas fa-fw fa-user' as usual. Only the defaults provided by the package are Bootstrap Icons based.

TIP

The icon_color attribute accepts the eight Bootstrap 5.3 theme colors (primary, secondary, success, danger, warning, info, light and dark). Any color of the AdminLTE v4 extended palette (navy, olive, sky, teal, ...) requires the assets.extended_colors option to be enabled on the config/adminlte.php file.

Unlike the blade components, the menu attributes are not translated from the AdminLTE v3 palette: the value is copied verbatim into the class name. So an old color name such as lightblue or maroon needs both assets.extended_colors and assets.extended_colors_v3_aliases to be enabled. Otherwise, use the v4 name (sky, pink, ...). The same applies to the label_color attribute.

The id Attribute: ​

This attribute is optional, and just provide a way to add an id to the element that wraps the menu item, generally a <li> tag. This can be useful when you need to target the menu item from Javascript in order to perform updates on it.

php
[
    'text' => 'profile',
    'url' => 'user/profile',
    'id' => 'profile-id',
]

The key Attribute: ​

In order to place an item dynamically you can use the key attribute, with this attribute you set an unique identifier for the item. Then, you can use this identifier later to add new items before or after the item represented by this key identifier. For more details, checkout the section Dynamic Menu Config.

The label and label_color Attributes: ​

The label attribute provides a way to setup a right aligned badge for the menu item. The label_color is used to configure the badge color (it is rendered as a Bootstrap 5.3 text-bg-{color} class, primary when not defined), example:

php
[
    'text' => 'pages',
    'url' => 'admin/pages',
    'icon' => 'bi bi-file-earmark',
    'label' => 4,
    'label_color' => 'success',
]

The model Attribute: ​

This attribute is only meaningful together with the can attribute. Its value is passed as the extra argument of the Gate::any() check performed by the GateFilter, which is what Laravel Policies need in order to resolve the policy class. The value may be a model class name (for the policy actions that do not require a model instance) or a model instance (only possible on a dynamic menu configuration):

php
[
    'text' => 'Create Post',
    'url' => 'admin/posts/new',
    'can' => ['create'],
    'model' => \App\Models\Post::class,
]

When the attribute is not defined, the can permissions are checked without any extra argument. See Side Notes About Laravel Policies Support for a complete walkthrough.

The route Attribute: ​

You can use this attribute to assign a Laravel route name to a link item, if you choose to use this attribute, then don't mix it with the url attribute, for example:

php
[
    'text' => 'Profile',
    'route' => 'admin.profile',
    'icon' => 'bi bi-person',
]

Even more, you can define a route with parameters using an array where the first value is the route name and the second value an array with the parameters, as shown next:

php
[
    'text' => 'Profile',
    'route' => ['admin.profile', ['userID' => '673']],
    'icon' => 'bi bi-person',
]

The shift Attribute: ​

CAUTION

This attribute will be dropped on the future. So, you should favor the usage of the classes attribute instead.

This attribute provides a way to inject classes into the a.nav-link element of a given menu item (the same element the classes attribute reaches on a link item, not the wrapping <li>). It's intended to allow the specification of custom margins on a submenu item to create an indented appearance. Example:

php
[
    'text' => 'Personnel Management',
    'submenu' => [
        [
            'text' => 'Invites',
            'shift' => 'ms-3',
            'submenu' => [
                [
                    'text' => 'View Invites',
                    'route' => 'invite.index',
                    'icon' => 'bi bi-people',
                    'shift' => 'ms-4',
                ],
            ],
        ],
    ],
]

The submenu Attribute: ​

This attribute provides a way to create a menu item containing child items. With this feature you can create nested menus. You can create a menu with items in the sidebar and/or the top navbar. Example:

php
[
    'text' => 'menu',
    'icon' => 'bi bi-share',
    'submenu' => [
        [
            'text' => 'child 1',
            'url' => 'menu/child1',
        ],
        [
            'text' => 'child 2',
            'url' => 'menu/child2',
        ],
    ],
]

The target Attribute: ​

This attribute is optional and intended to be used only with link items. It represents the underlying HTML target attribute for a link item. As an example, you can setup this attribute to the '_blank' value in order to open the link in a new tab.

The text Attribute: ​

The value of this attribute is just the descriptive text for a menu item (except for headers). The text attribute supports translations, as explained on the Translations section.

The topnav, topnav_right and topnav_user Attributes: ​

It's possible to add menu items to the top navigation while the sidebar is enabled, you need to set the topnav attribute to true for this feature. Also, you can set the topnav_right attribute for put the item on the right side of the topnav or set the topnav_user attribute to place the menu item in the user menu (above the user-body).

NOTE

When the top navigation layout is enabled, all menu items will appear in the top navigation.

The url Attribute: ​

The value of this attribute should be the URL for a link item. You can use a full URL with the domain part or without it. Don't mix this attribute with the route attribute. Examples:

php
[
    'text' => 'profile',
    'url' => 'http://my.domain.com/user/profile',
    'icon' => 'bi bi-person',
],
[
    'text' => 'change_password',
    'url' => 'admin/settings',
    'icon' => 'bi bi-lock',
],

A menu filter is a small class that receives every menu item, one by one, right before it is rendered, and returns it back possibly modified. It is how the package resolves the url of a route attribute, decides whether an item is active, or hides an item the current user is not allowed to see.

You can set the filters you want to include for rendering the menu using the filters configuration of the config file. You can also add your own custom filters to this array after you've created them. You can comment out the GateFilter if you don't want to use Laravel's built in Gate functionality. The current default set of menu filters is:

php
'filters' => [
    JeroenNoten\LaravelAdminLte\Menu\Filters\GateFilter::class,
    JeroenNoten\LaravelAdminLte\Menu\Filters\HrefFilter::class,
    JeroenNoten\LaravelAdminLte\Menu\Filters\SearchFilter::class,
    JeroenNoten\LaravelAdminLte\Menu\Filters\ActiveFilter::class,
    JeroenNoten\LaravelAdminLte\Menu\Filters\ClassesFilter::class,
    JeroenNoten\LaravelAdminLte\Menu\Filters\LangFilter::class,
    JeroenNoten\LaravelAdminLte\Menu\Filters\DataFilter::class,
],

If you need to use a custom menu filter, you can add your own menu filter to the previous array. This can be useful, for example, when you are using a third-party package for authorization (instead of the Laravel's Gate functionality). In order to provide more details, we are going to show an example of how you can configure the Laratrust Package. Start by creating your custom filter implementation:

IMPORTANT

Your custom filter needs to implement the FilterInterface provided by this package.

php
<?php

namespace MyApp;

use JeroenNoten\LaravelAdminLte\Menu\Filters\FilterInterface;
use Laratrust\Laratrust;

class MyMenuFilter implements FilterInterface
{
    public function transform($item)
    {
        if (isset($item['permission']) && ! Laratrust::isAbleTo($item['permission'])) {
            $item['restricted'] = true;
        }

        return $item;
    }
}

And then add the following configuration to the config/adminlte.php file:

php
'filters' => [
    ...
    JeroenNoten\LaravelAdminLte\Menu\Filters\ActiveFilter::class,
    JeroenNoten\LaravelAdminLte\Menu\Filters\HrefFilter::class,
    JeroenNoten\LaravelAdminLte\Menu\Filters\ClassesFilter::class,
    // Comment next line out to remove the Gate filter.
    //JeroenNoten\LaravelAdminLte\Menu\Filters\GateFilter::class,
    MyApp\MyMenuFilter::class,
]

NOTE

The example above sets the restricted attribute on the item. It is the internal flag the package reads to decide whether an item is rendered: any item carrying 'restricted' => true is dropped from the menu, whatever the reason your filter had. The shipped GateFilter sets exactly the same flag, so your own filter integrates with the rest of the pipeline without any extra work.

Dynamic Menu Config ​

It is also possible to configure the menu dynamically at runtime, for example in the boot method of any service provider or from a controller. You can add new menu items at the end of the menu, before or after a specific menu item, and also inside a menu item as a submenu item. You can use this feature when your menu is not created statically, for example when it depends on your database or the locale configuration.

It is also possible to combine both approaches, a static configured menu with dynamics modifications. The menu will simply be concatenated and the order of the service providers will determine the order in the menu.

The dynamic configuration is done from a listener of the BuildingMenu event that this package dispatches, which hands you a menu builder object on its $menu property. The events page shows the two places a listener can live on a Laravel 12 application; the examples below only show the body of the listener.

The available menu builder methods are:

  • add(...$newItems)

    Adds one or multiple menu items, you can use the item's attributes to place the item/s in the sidebar or the topnav menus (right, left or user menu).

  • addAfter($itemKey, ...$newItems)

    Adds one or multiple menu items after a specific menu item (distinguished by his key attribute).

  • addBefore($itemKey, ...$newItems)

    Adds one or multiple menu items before a specific menu item (distinguished by his key attribute).

  • addIn($itemKey, ...$newItems)

    Adds one or multiple menu items inside a specific menu item (distinguished by his key attribute) as submenu or child item/s.

  • remove($itemKey)

    Removes one specific menu item (distinguished by his key attribute).

  • itemKeyExists($itemKey)

    Checks if a specific menu item exists, searched by the key attribute.

In the next example we give a basic overview of how to use the methods. First, we add a key attribute to a particular menu item.

php
[
    'key' => 'pages',
    'text' => 'Pages',
    'url' => 'admin/pages',
    'icon' => 'bi bi-file-earmark',
],

Then, we're going add the next menu items.

  1. Account Settings after Pages
  2. Notifications inside Account Settings
  3. Profile before Notifications

So, on the boot() method of a service provider of your application (for example app/Providers/AppServiceProvider.php), we can write the next lines in order to add the mentioned new items:

php
use Illuminate\Support\Facades\Event;
use JeroenNoten\LaravelAdminLte\Events\BuildingMenu;

Event::listen(BuildingMenu::class, function (BuildingMenu $event) {

    $event->menu->addAfter('pages', [
        'key' => 'account_settings',
        'header' => 'Account Settings',
    ]);

    $event->menu->addIn('account_settings', [
        'key' => 'account_settings_notifications',
        'text' => 'Notifications',
        'url' => 'account/edit/notifications',
    ]);

    $event->menu->addBefore('account_settings_notifications', [
        'key' => 'account_settings_profile',
        'text' => 'Profile',
        'url' => 'account/edit/profile',
    ]);
});

The event-based approach is used to make sure that the code that builds the menu runs only when the admin panel is actually displayed, and not on every request (for example on AJAX calls to the server).

Config at the Event Service Provider ​

IMPORTANT

The next examples are somehow obsolete for the current Laravel state of art. The app/Providers/EventServiceProvider.php file does not exist anymore on a fresh Laravel 12 application, where you usually define a Listener class for the BuildingMenu event, as explained on the events page and on the Laravel's Events Documentation. However, the code may still be used as reference, and it keeps working on the projects that still have that file.

To configure the menu at runtime on the Laravel app/Providers/EventServiceProvider.php, just register a handler or callback for the BuildingMenu event. For example, in the boot() method:

php
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
use JeroenNoten\LaravelAdminLte\Events\BuildingMenu;

class EventServiceProvider extends ServiceProvider
{
    /**
     * Register any events for your application.
     *
     * @return void
     */
    public function boot()
    {
        Event::listen(BuildingMenu::class, function (BuildingMenu $event) {
            // Add some items to the menu...
            $event->menu->add('MAIN NAVIGATION');
            $event->menu->add([
                'text' => 'Blog',
                'url' => 'admin/blog',
            ]);
        });
    }
}

The attributes for a menu item are the same explained previously. Here is a more practical example that uses translations and the database:

php
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
use JeroenNoten\LaravelAdminLte\Events\BuildingMenu;

class EventServiceProvider extends ServiceProvider
{
    /**
     * Register any events for your application.
     *
     * @return void
     */
    public function boot()
    {
        Event::listen(BuildingMenu::class, function (BuildingMenu $event) {

            $event->menu->add(trans('menu.pages'));

            $items = Page::all()->map(function (Page $page) {
                return [
                    'text' => $page['title'],
                    'url' => route('admin.pages.edit', $page)
                ];
            });

            $event->menu->add(...$items);
        });
    }
}

Side Notes About Laravel Policies Support ​

With Laravel Policies, you can create a policy class that will be attached to a model according naming conventions. For example, consider the next policies for a Post model:

php
<?php

namespace App\Policies;

use App\Models\Post;
use App\Models\User;

class PostPolicy
{
    /**
     * Determine whether the user can create posts.
     */
    public function create(User $user): bool
    {
        return $user->canCreatePost();
    }

    /**
     * Determine whether the user can update a post.
     */
    public function update(User $user, Post $post): bool
    {
        if ($user->isAdmin()) {
            return true;
        }

        return $user->id === $post->user_id;
    }

    /**
     * Determine whether the user can delete a post.
     */
    public function delete(User $user, Post $post): bool
    {
        if ($user->isAdmin()) {
            return true;
        }

        return $user->id === $post->user_id;
    }
}

After defining the policies, we can check whether a user has permission to perform some action using several ways (read this for details), some examples:

php
// Check whether a user can create a post via the user model.
$user->can('create', \App\Models\Post::class);

// Check whether a user can create a post via the Gate facade.
Gate::authorize('create', \App\Models\Post::class);

// Check whether a user can update a post via the user model.
$user->can('update', $post);

// Check whether a user can update a post via the Gate facade.
Gate::authorize('update', $post);

Now let's see how this is supported in the menu configuration by using the can attribute.

Support to Policies Actions That Don't Require Models ​

If you're using a static menu configuration, the can attribute may be used with policies actions that don't require models. The next example shows a menu item that will only be visible for users that can create posts, as defined by the previous App\Policies\PostPolicy.

php
[
    'text' => 'Create Post',
    'url' => '...',
    'can' => ['create'],
    'model' => \App\Models\Post::class,
],

Support to Policies Actions That Require Models: ​

The can attribute may be used with policies actions that require models, but only if you're defining your menu dynamically. The next example shows a menu item that will only be visible for users that can manage (update, delete) a particular post, as defined by the previous App\Policies\PostPolicy. Note this example assumes we have a Listener for the BuildingMenu event dispatched by this package:

php
<?php

namespace App\Listeners;

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use JeroenNoten\LaravelAdminLte\Events\BuildingMenu;

class SetupAdminLteMenu
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param  BuildingMenu  $event
     * @return void
     */
    public function handle(BuildingMenu $event)
    {
        // Retrieve the most popular post.
        // The getMostPopularPost() method should be defined in the Post model.

        $post = \App\Models\Post::getMostPopularPost();

        // Add new item to the menu, dynamically...

        $event->menu->add([
            'text' => 'Manage Most Popular Post',
            'url' => '...',
            'can' => ['update', 'delete'],
            'model' => $post,
        ]);
    }
}

Thanks to @ruanpepe for contributing with the base of this documentation: