Courses

Filament 3 From Scratch: Practical Course

Menu Items: Ordering, Grouping, Icons, Badges

Summary of this lesson:
- Configuring top vs side navigation
- Ordering and grouping menu items
- Customizing menu icons
- Adding badges to menu items

For now, in this course, we've been generating Filament Resources with menu items being auto-generated for us. They have the same icon and a pretty random order. In this lesson, let's learn how to customize it all.


Menu: Left or Top?

So, for now, we have this view in the left menu:

First quick change: did you know we can easily change the menu from the left to the top? It's configurable by adding topNavigation() in the main AdminPanelProvider:

app/Providers/Filament/AdminPanelProvider.php:

public function panel(Panel $panel): Panel
{
return $panel
->default()
->id('admin')
->path('admin')
->login()
->registration()
->topNavigation()

With this simple change, the menu looks like this:


Ordering Menu Items

Next, if you don't specify any order for menu items, they are ordered alphabetically.

To change that, add an integer property $navigationSort in each Filament Resource, representing their order position.

For example, I want to sort the menu items in the order they would be used: from the most often (Orders) to the least often (Tags).

app/Filament/Resources/OrderResource.php:

class OrderResource extends Resource
{
protected static ?int $navigationSort = 1;
 
// ...

app/Filament/Resources/ProductResource.php:

class ProductResource extends Resource
{
protected static ?int $navigationSort = 2;
 
// ...

app/Filament/Resources/CategoryResource.php:

class CategoryResource extends Resource
{
protected static ?int $navigationSort = 3;
 
// ...

app/Filament/Resources/TagResource.php:

class TagResource extends Resource
{
protected static ?int $navigationSort = 4;
 
// ...

And there you go, the result!


Grouping Menu Items

If you have many menu items, it's pretty helpful to group them like parent-children.

To do that, you need to specify a group name as a string $navigationGroup property in each Resource class you want in that group.

For example, if I want to separate "Categories" and "Tags" into their own group "Classifiers", I do this:

app/Filament/Resources/CategoryResource.php:

class CategoryResource extends Resource
{
protected static ?string $navigationGroup = 'Classifiers';
 
// ...

app/Filament/Resources/TagResource.php:

class TagResource extends Resource
{
protected static ?string $navigationGroup = 'Classifiers';
 
// ...

These changes lead to this grouping:

As you can see, it's not required for all menu items to have any navigation group. You can leave some of them ungrouped.


Change Menu Icons

Each menu item has an icon. The default one is heroicon-o-rectangle-stack. Interestingly, the properties discussed above, like $navigationGroup and $navigationSort, are not visible right away in the Filament Resource class until you define them, but $navigationIcon is visible immediately in the class generated by make:filament-resource.

Let's change the icons to some other ones. You may choose icons from this Blade UI Kit page.

app/Filament/Resources/CategoryResource.php:

class CategoryResource extends Resource
{
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationIcon = 'heroicon-o-folder';
 
// ...

app/Filament/Resources/TagResource.php:

class TagResource extends Resource
{
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationIcon = 'heroicon-o-tag';
 
// ...

app/Filament/Resources/OrderResource.php:

class OrderResource extends Resource
{
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationIcon = 'heroicon-o-shopping-cart';
 
// ...

We leave the ProductResource with the default icon so that you would see the difference. Let's see how it looks:


Add Badges to Menu Items

Sometimes, you need a number in the menu: the number of new messages, unread notifications, or something similar.

For that, you can specify a method getNavigationBadge(), which would return a string or a number you want.

app/Filament/Resources/OrderResource.php:

class OrderResource extends Resource
{
public static function getNavigationBadge(): ?string
{
return Order::whereDate('created_at', today())->count();
}

So, if we have one new order today, it will show like this:

Also, it doesn't have to be a number. It may be just the text, like "New":

app/Filament/Resources/OrderResource.php:

class OrderResource extends Resource
{
public static function getNavigationBadge(): ?string
{
return Order::whereDate('created_at', today())->count() ? 'NEW' : '';
}

Here's the visual result:


Permissions: Hide Menu Items by Role

In general, roles and permissions are a pretty deep topic, and we will discuss it separately.

But for now, what you need to know is you can show/hide the menu item based on Laravel Policies.

For example, if you want to show some menu items only for users with users.is_admin = 1 value, you can define the viewAny() method in your Policy:

php artisan make:policy OrderPolicy --model=Order

app/Policies/OrderPolicy.php:

namespace App\Policies;
 
use App\Models\Order;
use App\Models\User;
use Illuminate\Auth\Access\Response;
 
class OrderPolicy
{
public function viewAny(User $user): bool
{
return $user->is_admin == 1;
}
}

Then the users.is_admin = 0 users will not see the menu "Orders" and won't be able to access any of its features.


Add Static Pages to Menu

Another sub-topic: not directly about menus, but I decided to add it to this lesson. What if you want static pages like "About project" or "Contact us," which are not CRUDs or Filament Resources?

You can generate them as Filament Pages like this:

php artisan make:filament-page ContactUs

Here's the default code it would generate:

app/Filament/Pages/ContactUs.php:

namespace App\Filament\Pages;
 
use Filament\Pages\Page;
 
class ContactUs extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-document-text';
 
protected static string $view = 'filament.pages.contact-us';
}

And then the almost-empty Blade file:

resources/views/filament/pages/contact-us.blade.php:

<x-filament-panels::page>
 
</x-filament-panels::page>

And then you can add your content inside that <x-filament-panels::page> block:

resources/views/filament/pages/contact-us.blade.php:

<x-filament-panels::page>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas at nisl faucibus neque ornare interdum.
 
Pellentesque malesuada, turpis eget placerat tincidunt, felis turpis imperdiet quam, sed pharetra erat ex eu nisi.
 
Aenean ex sapien, scelerisque sit amet lectus in, placerat tempor dui. Nam malesuada tempor condimentum.
</x-filament-panels::page>

Here's the visual result:

And, of course, you can customize that "Contact Us" menu item by experimenting with all the properties discussed above: navigation label, sort, groups, etc.


So, these are the main ways to customize the menus in Filament.

Previous: Form Layouts: Columns, Sections, Tabs, Wizards
avatar
Wilko van der Ploeg

When I want to have an app suitable for multiple languages, it's common to use the __ function __('Hello World!')

However since the $navigationString variables are static, I can't assign a value as a result of a function.

Is there any way to create menu groups with 'translatable' group strings?

avatar

If you have a static variable - the is most likely a getXXXXLabel function available. For example on resources, to get navigation name:

    public static function getNavigationLabel(): ?string

Inside you can return the string that will be used as the label

avatar
You can use Markdown
avatar

Is it possible to conditionally hide a navigation badge? I have a nav item called 'settings' that I want a new user to configure first. It would be great to add a badge to this nav item to indicate that they need to do this first, if they haven't completed the form yet. After the form is submitted, the badge goes away.

avatar
You can use Markdown
avatar

How can I customize the theme of the sidebar menu?

Image Description

avatar
You can use Markdown
avatar
Jean Carlos Charão Sabino

Hello Povilas,

First of all, I want to congratulate you on the excellent course! I'm really enjoying the content and the way you present the concepts. Your clear teaching style and practical examples have been incredibly helpful for my learning.

I have a question regarding the implementation of a menu item to log out/exit the system. Could you guide me on how to do this in the most appropriate way?

Thank you once again for the course and for your dedication to teaching us!

avatar
You can use Markdown
avatar

Is it possible to have a Top navigation that displays a secondary navigation along the side that differs for each TOP selection?

Like if each top navigation represented a different department such as HR, legal, marketing. etc where the side options would differ for each.

avatar

You can definitely do that using render hooks:

https://filamentexamples.com/tutorial/render-hooks-cheat-sheet

avatar
You can use Markdown
avatar
You can use Markdown