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.
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:
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!
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.
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:
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:
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.
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.