Appearance

Menu

Video guide

Basics

Menu is the foundation for navigation in the admin panel, so we have tried to create a flexible system that allows you to fully customize the menu for different pages and users.

The navigation menu is configured in a class that extends MoonShine\Laravel\Layouts\AppLayout through the menu() method.

During the installation of the admin panel, depending on the configurations you choose, a class App\MoonShine\Layouts\MoonShineLayout will be created, which already contains the menu() method.

In the future, if necessary, you can create other Layouts for specific pages.

Also try an alternative way to generate the menu using autoupload.

Items

To add a menu item, you need to use the class MenuItem.

make(
Closure|MenuFillerContract|string $filler,
Closure|string $label = null,
string $icon = null,
Closure|bool $blank = false
)
make(
Closure|MenuFillerContract|string $filler,
Closure|string $label = null,
string $icon = null,
Closure|bool $blank = false
)
  • $filler - an element for generating the URL,
  • $label - the name of the menu item (default is taken from the filler's getTitle() method),
  • $icon - an icon for the menu item,
  • $blank - open in a new tab.

Any class that implements the MenuFillerContract interface can be passed as $filler. By default, ModelResource and Page.

 namespaces
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuItem::make(MoonShineUserResource::class),
MenuItem::make(fn() => route('home'), 'Home'),
MenuItem::make('https://moonshine-laravel.com/docs', 'Docs', blank: true),
MenuItem::make('https://laravel.com/docs', 'Laravel Docs', blank: true),
];
}
 namespaces
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuItem::make(MoonShineUserResource::class),
MenuItem::make(fn() => route('home'), 'Home'),
MenuItem::make('https://moonshine-laravel.com/docs', 'Docs', blank: true),
MenuItem::make('https://laravel.com/docs', 'Laravel Docs', blank: true),
];
}

If the menu is created for ModelResource or CrudResource, the first page declared in the pages() method will be used for the menu item.

Groups

Menu items can be grouped together. To do this, use the MenuGroup class.

make(
Closure|string $label,
iterable $items,
string|null $icon = null,
)
make(
Closure|string $label,
iterable $items,
string|null $icon = null,
)
  • $label - the name of the group,
  • $items - an array of menu components,
  • $icon - an icon for the group.
 namespaces
use MoonShine\MenuManager\MenuGroup;
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuGroup::make('System', [
MenuItem::make(MoonShineUserResource::class),
MenuItem::make(MoonShineUserRoleResource::class),
])
];
}
 namespaces
use MoonShine\MenuManager\MenuGroup;
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuGroup::make('System', [
MenuItem::make(MoonShineUserResource::class),
MenuItem::make(MoonShineUserRoleResource::class),
])
];
}

You can also add items to the group using the setItems() method.

setItems(iterable $items)
setItems(iterable $items)
 namespaces
use MoonShine\MenuManager\MenuGroup;
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuGroup::make('System')->setItems([
MenuItem::make(MoonShineUserResource::class),
MenuItem::make(MoonShineUserRoleResource::class),
])
];
}
 namespaces
use MoonShine\MenuManager\MenuGroup;
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuGroup::make('System')->setItems([
MenuItem::make(MoonShineUserResource::class),
MenuItem::make(MoonShineUserRoleResource::class),
])
];
}

To create a multi-level menu, groups can be nested.

Divider

Menu items can be visually separated using MenuDivider.

/**
* @param (Closure(MenuElementContract $context): string)|string $label
*/
make(Closure|string $label = '')
/**
* @param (Closure(MenuElementContract $context): string)|string $label
*/
make(Closure|string $label = '')
 namespaces
use MoonShine\MenuManager\MenuDivider;
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuItem::make(MoonShineUserResource::class),
MenuDivider::make(),
MenuItem::make(MoonShineUserRoleResource::class),
];
}
 namespaces
use MoonShine\MenuManager\MenuDivider;
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuItem::make(MoonShineUserResource::class),
MenuDivider::make(),
MenuItem::make(MoonShineUserRoleResource::class),
];
}

Icon

An icon can be assigned to both a menu item and a group. This can be implemented in several ways.

Through parameter

An icon can be set by passing the name as the third parameter in the static method make().

 namespaces
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuItem::make(MoonShineUserResource::class, icon: 'users'),
MenuItem::make(MoonShineUserRoleResource::class, icon: 'hashtag')
];
}
 namespaces
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuItem::make(MoonShineUserResource::class, icon: 'users'),
MenuItem::make(MoonShineUserRoleResource::class, icon: 'hashtag')
];
}

Through method

You can use the icon() method.

icon(
string $icon,
bool $custom = false,
?string $path = null,
)
icon(
string $icon,
bool $custom = false,
?string $path = null,
)
  • $icon - the name of the icon or HTML (if custom mode is used),
  • $custom - custom mode,
  • $path - the path to the directory where the Blade templates of icons are stored.
 namespaces
namespace App\MoonShine\Layouts;
 
use MoonShine\Laravel\Layouts\AppLayout;
use MoonShine\MenuManager\MenuGroup;
use MoonShine\MenuManager\MenuItem;
 
final class MoonShineLayout extends AppLayout
{
// ...
 
protected function menu(): array
{
return [
MenuGroup::make('System', [
MenuItem::make(MoonShineUserResource::class)
->icon('users'),
MenuItem::make(MoonShineUserRoleResource::class)
->icon(svg('path-to-icon-pack')->toHtml(), custom: true),
])
->icon('cog', path: 'icons')
];
}
}
 namespaces
namespace App\MoonShine\Layouts;
 
use MoonShine\Laravel\Layouts\AppLayout;
use MoonShine\MenuManager\MenuGroup;
use MoonShine\MenuManager\MenuItem;
 
final class MoonShineLayout extends AppLayout
{
// ...
 
protected function menu(): array
{
return [
MenuGroup::make('System', [
MenuItem::make(MoonShineUserResource::class)
->icon('users'),
MenuItem::make(MoonShineUserRoleResource::class)
->icon(svg('path-to-icon-pack')->toHtml(), custom: true),
])
->icon('cog', path: 'icons')
];
}
}

Through attribute

An icon will be displayed for the menu item if the ModelResource, Page, or Resource class has the Icon attribute set and the icon has not been overridden by other means.

#[Icon('users')]
class MoonShineUserResource extends ModelResource
{
// ...
}
#[Icon('users')]
class MoonShineUserResource extends ModelResource
{
// ...
}

For more detailed information, refer to the section Icons.

Only icons

If you want to display menu items with only icons without text labels, use the onlyIcon() method.

/**
* @param (Closure(static $ctx): bool)|bool|null $condition
*/
onlyIcon(Closure|bool|null $condition = true)
/**
* @param (Closure(static $ctx): bool)|bool|null $condition
*/
onlyIcon(Closure|bool|null $condition = true)

For individual items

You can apply onlyIcon() to individual menu items.

 namespaces
namespace App\MoonShine\Layouts;
 
use MoonShine\Laravel\Layouts\AppLayout;
use MoonShine\MenuManager\MenuItem;
 
final class MoonShineLayout extends AppLayout
{
// ...
 
protected function menu(): array
{
return [
MenuItem::make('/', 'Dashboard', 'heroicons.home')
->onlyIcon(),
];
}
}
 namespaces
namespace App\MoonShine\Layouts;
 
use MoonShine\Laravel\Layouts\AppLayout;
use MoonShine\MenuManager\MenuItem;
 
final class MoonShineLayout extends AppLayout
{
// ...
 
protected function menu(): array
{
return [
MenuItem::make('/', 'Dashboard', 'heroicons.home')
->onlyIcon(),
];
}
}

For the entire menu

You can apply the icon-only mode to the entire menu when using autoload by passing the onlyIcons: true parameter to the autoloadMenu() method.

 namespaces
namespace App\MoonShine\Layouts;
 
use MoonShine\Laravel\Layouts\AppLayout;
 
final class MoonShineLayout extends AppLayout
{
// ...
 
protected function menu(): array
{
return $this->autoloadMenu(onlyIcons: true);
}
}
 namespaces
namespace App\MoonShine\Layouts;
 
use MoonShine\Laravel\Layouts\AppLayout;
 
final class MoonShineLayout extends AppLayout
{
// ...
 
protected function menu(): array
{
return $this->autoloadMenu(onlyIcons: true);
}
}

When hovering over a menu item with the onlyIcon() mode enabled, a tooltip with the full label text is displayed.

If a menu item does not have an icon set, the squares-2x2 icon will be used by default.

Badge

You can also add a badge to a menu item.

Through menu item

To add a badge to a menu item, use the badge() method, which takes a closure as a parameter.

/**
* @param Closure(MenuElementContract $context): string|int|float|null $value
*/
badge(Closure|string|int|float|null $value)
/**
* @param Closure(MenuElementContract $context): string|int|float|null $value
*/
badge(Closure|string|int|float|null $value)
 namespaces
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuItem::make(CommentResource::class)
->badge(fn() => Comment::count())
];
}
 namespaces
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuItem::make(CommentResource::class)
->badge(fn() => Comment::count())
];
}

Translation

To translate menu items, you need to pass the translation key as the name and add the translatable() method.

translatable(string $key = '')
translatable(string $key = '')
 namespaces
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuItem::make(CommentResource::class, 'menu.Comments')
->translatable()
// or
MenuItem::make(CommentResource::class, 'Comments')
->translatable('menu')
];
}
 namespaces
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuItem::make(CommentResource::class, 'menu.Comments')
->translatable()
// or
MenuItem::make(CommentResource::class, 'Comments')
->translatable('menu')
];
}
// lang/en/menu.php
 
return [
'Comments' => 'Comments',
];
// lang/en/menu.php
 
return [
'Comments' => 'Comments',
];

You can use Laravel's translation features for translating menu badges.

 namespaces
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuItem::make(CommentResource::class)
->badge(fn() => __('menu.badge.new'))
];
}
 namespaces
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuItem::make(CommentResource::class)
->badge(fn() => __('menu.badge.new'))
];
}

Open in a new tab

You can specify a flag for the menu item to indicate whether to open the link in a new tab. This can be implemented in several ways.

Through parameter

The flag can be set by passing the fourth parameter true/false or a closure in the static method make().

 namespaces
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuItem::make('https://moonshine-laravel.com/docs', 'MoonShine Docs', 'heroicons.arrow-up', true),
MenuItem::make('https://laravel.com/docs', 'Laravel Docs', blank: fn() => true),
];
}
 namespaces
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuItem::make('https://moonshine-laravel.com/docs', 'MoonShine Docs', 'heroicons.arrow-up', true),
MenuItem::make('https://laravel.com/docs', 'Laravel Docs', blank: fn() => true),
];
}

Through method

You can use the blank() method.

/**
* @param (Closure(MenuElementContract $context): bool)|bool $blankCondition
*/
blank(Closure|bool $blankCondition = true)
/**
* @param (Closure(MenuElementContract $context): bool)|bool $blankCondition
*/
blank(Closure|bool $blankCondition = true)
 namespaces
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuItem::make('https://moonshine-laravel.com/docs', 'MoonShine Docs', 'heroicons.arrow-up', true),
MenuItem::make('https://laravel.com/docs', 'Laravel Docs')
->blank(fn() => true),
];
}
 namespaces
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuItem::make('https://moonshine-laravel.com/docs', 'MoonShine Docs', 'heroicons.arrow-up', true),
MenuItem::make('https://laravel.com/docs', 'Laravel Docs')
->blank(fn() => true),
];
}

Display condition

You can display menu items based on a condition using the canSee() method.

/**
* @param Closure(MenuElementContract $context): bool $callback
*/
canSee(Closure $callback)
/**
* @param Closure(MenuElementContract $context): bool $callback
*/
canSee(Closure $callback)
 namespaces
use MoonShine\MenuManager\MenuDivider;
use MoonShine\MenuManager\MenuGroup;
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuGroup::make('System', [
MenuItem::make(MoonShineUserResource::class),
MenuDivider::make()
->canSee(fn() => true),
MenuItem::make(MoonShineUserRoleResource::class)
->canSee(fn() => false)
])
->canSee(static fn(): bool => request()->user('moonshine')?->id === 1)
];
}
 namespaces
use MoonShine\MenuManager\MenuDivider;
use MoonShine\MenuManager\MenuGroup;
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuGroup::make('System', [
MenuItem::make(MoonShineUserResource::class),
MenuDivider::make()
->canSee(fn() => true),
MenuItem::make(MoonShineUserRoleResource::class)
->canSee(fn() => false)
])
->canSee(static fn(): bool => request()->user('moonshine')?->id === 1)
];
}

Active item

A menu item becomes active if it matches the url, but the whenActive() method allows you to forcibly make an item active.

/**
* @param Closure(string $path, string $host, MenuElementContract $context): bool $when
*/
whenActive(Closure $when)
/**
* @param Closure(string $path, string $host, MenuElementContract $context): bool $when
*/
whenActive(Closure $when)
 namespaces
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuItem::make('/endpoint', 'Label')
->whenActive(
fn() => request()->fullUrlIs('*admin/endpoint/*')
),
];
}
 namespaces
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuItem::make('/endpoint', 'Label')
->whenActive(
fn() => request()->fullUrlIs('*admin/endpoint/*')
),
];
}

Attributes

Groups and menu items, like other components, can have custom attributes assigned.

For more detailed information, refer to the section Component Attributes.

 namespaces
use MoonShine\MenuManager\MenuGroup;
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuGroup::make('System')->setItems([
MenuItem::make(MoonShineUserResource::class),
MenuItem::make(MoonShineUserRoleResource::class)
->customAttributes(['class' => 'group-li-custom-class'])
])
->setAttribute('data-id', '123')
->class('group-li-custom-class')
];
}
 namespaces
use MoonShine\MenuManager\MenuGroup;
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuGroup::make('System')->setItems([
MenuItem::make(MoonShineUserResource::class),
MenuItem::make(MoonShineUserRoleResource::class)
->customAttributes(['class' => 'group-li-custom-class'])
])
->setAttribute('data-id', '123')
->class('group-li-custom-class')
];
}

Change button

A menu item is an ActionButton and you can change its attributes using the changeButton() method.

/**
* @param Closure(ActionButtonContract $button): ActionButtonContract $callback
*/
changeButton(Closure $callback)
/**
* @param Closure(ActionButtonContract $button): ActionButtonContract $callback
*/
changeButton(Closure $callback)
 namespaces
use MoonShine\MenuManager\MenuItem;
use MoonShine\UI\Components\ActionButton;
 
protected function menu(): array
{
return [
MenuItem::make('/endpoint', 'Label')
->changeButton(static fn(ActionButton $button) => $button->class('new-item')),
];
}
 namespaces
use MoonShine\MenuManager\MenuItem;
use MoonShine\UI\Components\ActionButton;
 
protected function menu(): array
{
return [
MenuItem::make('/endpoint', 'Label')
->changeButton(static fn(ActionButton $button) => $button->class('new-item')),
];
}

Some parameters of ActionButton, such as url, badge, icon, and others are overridden in the system. To change them, use the corresponding methods.

Custom view

If you need to change the view using a fluent interface, you can use the customView() method.

customView(string $path)
customView(string $path)
  • $path - the path to the Blade template.
 namespaces
use MoonShine\MenuManager\MenuGroup;
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuGroup::make('Group', [
MenuItem::make('/endpoint', 'Label')
->customView('admin.custom-menu-item'),
])
->customView('admin.custom-menu-group'),
];
}
 namespaces
use MoonShine\MenuManager\MenuGroup;
use MoonShine\MenuManager\MenuItem;
 
protected function menu(): array
{
return [
MenuGroup::make('Group', [
MenuItem::make('/endpoint', 'Label')
->customView('admin.custom-menu-item'),
])
->customView('admin.custom-menu-group'),
];
}

To activate an alternative menu creation option, replace the array in the menu() method by calling autoloadMenu() method.

For menu autoloading to work, you must also enable autoloading of resources and pages.

protected function menu(): array
{
return $this->autoloadMenu();
}
protected function menu(): array
{
return $this->autoloadMenu();
}

If you need to skip a page or resource in the menu, use SkipMenu attribute.

 namespaces
use MoonShine\MenuManager\Attributes\SkipMenu;
 
#[SkipMenu]
class ProfilePage extends Page {}
 namespaces
use MoonShine\MenuManager\Attributes\SkipMenu;
 
#[SkipMenu]
class ProfilePage extends Page {}

If you need to wrap pages or resources into groups, use the Group attribute. The items will be grouped by name. You can also specify the icon and the translatable flag in the attribute.

 namespaces
use MoonShine\MenuManager\Attributes\Group;
 
#[Group('moonshine::ui.profile', 'users', translatable: true)]
class ProfilePage extends Page {}
 namespaces
use MoonShine\MenuManager\Attributes\Group;
 
#[Group('moonshine::ui.profile', 'users', translatable: true)]
class ProfilePage extends Page {}

If you need to display a menu item by condition, use CanSee attribute. Add a method in the resource or page that will be responsible for the display condition.

 namespaces
use MoonShine\MenuManager\Attributes\CanSee;
 
#[CanSee(method: 'someMethod')]
class ArticleResource extends ModelResource
{
public function someMethod(): bool
{
return false;
}
}
 namespaces
use MoonShine\MenuManager\Attributes\CanSee;
 
#[CanSee(method: 'someMethod')]
class ArticleResource extends ModelResource
{
public function someMethod(): bool
{
return false;
}
}

If you need to set the order of the menu items, use Order attribute.

 namespaces
use MoonShine\MenuManager\Attributes\Order;
 
#[Order(1)]
class ArticleResource extends ModelResource {}
 namespaces
use MoonShine\MenuManager\Attributes\Order;
 
#[Order(1)]
class ArticleResource extends ModelResource {}

If you need to add a badge to a menu item, use the Badge attribute.

 namespaces
use MoonShine\MenuManager\Attributes\Badge;
 
#[\MoonShine\MenuManager\Attributes\Badge('new')]
class ArticleResource extends ModelResource {}
 namespaces
use MoonShine\MenuManager\Attributes\Badge;
 
#[\MoonShine\MenuManager\Attributes\Badge('new')]
class ArticleResource extends ModelResource {}