Multi-level Hierarchical Navigation Groups

Is it possible to have multiple levels of groups in the navigation menu or must there only be a top level of groups with one level of items inside? IOW is there a way to create a navigation group inside a navigation group, then add items to it?
18 Replies
toeknee
toeknee17mo ago
You can, however, you need to create the sub levels manually and not registering them automatically.
Mike Scott
Mike ScottOP17mo ago
Yes, I realised it had to be done manually but I've tried it various ways in my AppServiceProvider and couldn't get it to work. I can't see how to add a group to a group. For example, I tried this but no menu appears:
public function boot(): void
{
Filament::serving(function() {
Filament::registerNavigationGroups([
NavigationGroup::make('Top Level')->items([
NavigationGroup::make('Sub Level')->items([
NavigationItem::make('Google')
->url('https://google.com')
])
])
]);
});
}
public function boot(): void
{
Filament::serving(function() {
Filament::registerNavigationGroups([
NavigationGroup::make('Top Level')->items([
NavigationGroup::make('Sub Level')->items([
NavigationItem::make('Google')
->url('https://google.com')
])
])
]);
});
}
toeknee
toeknee17mo ago
Why doesn't that work?
Mike Scott
Mike ScottOP17mo ago
I've no idea. No menu appears.
toeknee
toeknee17mo ago
You placed it in the AppServiceProvider right? I would remove the register navigation groups wrapper I think, they are top level single array
Mike Scott
Mike ScottOP17mo ago
Yes, this is in AppServiceProvider::boot(). Removing the registerNavigationGroups() wrapper doesn't work either:
public function boot(): void
{
Filament::serving(function () {
NavigationGroup::make('Top Level')->items([
NavigationGroup::make('Sub Level')->items([
NavigationItem::make('Google')
->url('https://google.com')
])
]);
});
}
public function boot(): void
{
Filament::serving(function () {
NavigationGroup::make('Top Level')->items([
NavigationGroup::make('Sub Level')->items([
NavigationItem::make('Google')
->url('https://google.com')
])
]);
});
}
toeknee
toeknee17mo ago
If you do this:
NavigationItem::make('Horizon')
->url('/horizon')
->openUrlInNewTab(true)
->icon('fluentui-document-queue-multiple-20')
->group('Settings')
->sort(0),
NavigationItem::make('Horizon')
->url('/horizon')
->openUrlInNewTab(true)
->icon('fluentui-document-queue-multiple-20')
->group('Settings')
->sort(0),
Does ti work?
Mike Scott
Mike ScottOP17mo ago
And trying to add NavigationGroup::make() to Filament::registerNavigationItems() doesn't work either, since NavigationGroup isn't a NavigationItem and you get: Filament\FilamentManager::Filament{closure}(): Argument #1 ($item) must be of type Filament\Navigation\NavigationItem, Filament\Navigation\NavigationGroup given If I add that code where exactly? I can add navigation items in Filament::registerNavigationItems() no problem. But I can't add groups.
toeknee
toeknee17mo ago
Ok as a test:
Filament::registerNavigationGroups([
'Settings'
]);
Filament::registerNavigationGroups([
'Settings'
]);
php Then add your items as normal to Settings group, does that work? It's been a while since I did multi-nested but it did work
Mike Scott
Mike ScottOP17mo ago
Yes, I can add a group as a name and it creates a top-level menu. But how do I add another group to that group? I don't want to add items to that group, I want to add other groups and groups aren't items. I can easily create a single level of nesting, with items within a top-level group. But as I said at the start, I want to go deeper and add a group inside another group Can anyone confirm if it's even possible to have menu groups inside groups???
toeknee
toeknee17mo ago
It is posslbe.. I've done it before, just can't remember exactly how. Give me a min, I'll have a play
awcodes
awcodes17mo ago
I think to achieve this you will have to build the whole navigation from scratch with the NavigationBuilder. https://filamentphp.com/docs/2.x/admin/navigation#advanced-navigation-customization
Filament
Navigation - Admin Panel - Filament
The elegant TALL stack admin panel for Laravel artisans.
toeknee
toeknee17mo ago
Yes that's it, It's not a case of just adding parts you build the whole menu.
Patrick Boivin
Patrick Boivin17mo ago
IIRC you'll need some custom CSS for groups inside of groups, the alignment is a bit off
Patrick Boivin
Patrick Boivin17mo ago
But it works
Mike Scott
Mike ScottOP17mo ago
That's exactly what we've been discussing and I've been trying. Even building the navigation from scratch as it says in the docs, there's no way that I can see to add a group to a group. That's the piece I'm missing. What is the function that you call to add a group to a group? Thanks for the screenshot, apparently showing it's possible. But it'll take more than some CSS. No-one can tell me simply how to add a group to a group.
Patrick Boivin
Patrick Boivin17mo ago
Here's an edited down version of my custom nav:
class CustomNavigation
{
public static function build(): void
{
Filament::navigation(function (NavigationBuilder $builder): NavigationBuilder {
return $builder->items(
array_filter([
NavigationItem::make(__('Dashboard'))
->icon('heroicon-o-home')
->activeIcon('heroicon-s-home')
->isActiveWhen(fn (): bool => request()->routeIs('filament.pages.dashboard'))
->url(route('filament.pages.dashboard')),

// ...

($producsNavItems = self::productsNavItems()) ? NavigationGroup::make(__('Products'))
->items($producsNavItems)
->icon('heroicon-o-tag')
->collapsed()
: false,

// ...
])
);
});
}

// ...

private static function productsNavItems(): array
{
return array_filter([
TireResource::canViewAny() ? NavigationGroup::make(__('Tires'))
->items([
TireResource::getNavigationItems()[0]
->label(__('Tires List')),

ManufacturerTireResource::getNavigationItems()[0]
->label(__('Manufacturers')),
])
->collapsed()
: false,

// ...
]);
}
}
class CustomNavigation
{
public static function build(): void
{
Filament::navigation(function (NavigationBuilder $builder): NavigationBuilder {
return $builder->items(
array_filter([
NavigationItem::make(__('Dashboard'))
->icon('heroicon-o-home')
->activeIcon('heroicon-s-home')
->isActiveWhen(fn (): bool => request()->routeIs('filament.pages.dashboard'))
->url(route('filament.pages.dashboard')),

// ...

($producsNavItems = self::productsNavItems()) ? NavigationGroup::make(__('Products'))
->items($producsNavItems)
->icon('heroicon-o-tag')
->collapsed()
: false,

// ...
])
);
});
}

// ...

private static function productsNavItems(): array
{
return array_filter([
TireResource::canViewAny() ? NavigationGroup::make(__('Tires'))
->items([
TireResource::getNavigationItems()[0]
->label(__('Tires List')),

ManufacturerTireResource::getNavigationItems()[0]
->label(__('Manufacturers')),
])
->collapsed()
: false,

// ...
]);
}
}
Then in a service provider:
Filament::serving(function () {
CustomNavigation::build();

// ...
});
Filament::serving(function () {
CustomNavigation::build();

// ...
});
Mike Scott
Mike ScottOP17mo ago
Thank you for this. I can now see that it's not a trivial task, that out of the box Filament simply doesn't support multi-level menus. So now I'll look for another way to lay out my app.
Want results from more Discord servers?
Add your server