Navigator plugin screenshot
Dark mode ready
Multilingual support
Supports v5.x

Navigator

Community

Manage your panel's navigation from the panel itself: reorder groups and items with drag and drop, add custom links, and use any symbol as a menu icon — text markers, Blade icons, pasted SVG or uploaded PNG, JPG and WebP images — with no code and no deploy.

Tags: Developer Tool Panels
Supported versions:
5.x
Third-party plugin. This is built by the community, not the Filament team. Filament does not review, endorse, or vet the security of plugins outside the filament/ namespace. Review the source and install at your own risk. Found malware or an unresolved security issue the author won't address? Report it .
Komma SoftHouse avatar Author: Komma SoftHouse

Documentation

Filament Navigator — database-driven sidebar and topbar for Filament v5

Official documentation for Filament Navigator: the navigation of a Filament 5.x panel, run from the panel itself. Whoever administers the application rearranges the menu, renames it, adds links to anything — internal pages, external tools, documentation — and gives every entry its own symbol: a text marker, any Blade icon, pasted SVG or an uploaded PNG, JPG, WebP, GIF or AVIF, not just the icon set the developer installed. No code, no deploy, no view override: the change is live in the sidebar the moment it is saved.

Underneath, the sidebar (and optionally the topbar) is rendered by the plugin's own Livewire components from a per-panel configuration stored in the database, so the panel also stops looking like stock Filament.

Filament 5.x Laravel 13 PHP 8.4+ License

#What this plugin does

  • A menu edited at runtime, not in code. Groups, order, labels, visibility and role restrictions are rows in the database, arranged on a settings page with drag and drop — between groups, out of them, back to where the code put them. Every save refreshes the sidebar on the spot.
  • Links to anywhere. Add link puts any URL in the sidebar — a path of the application, an external tool, a help centre — with its own label, symbol, group, badge, role restriction and "open in a new tab". A registered page or resource can also have its URL overridden.
  • Any symbol, not only an icon set. Every group and item takes a text marker (;, , $, //), a Blade icon name from whatever icon packages the application has, pasted SVG markup or an uploaded image (PNG, JPG, WebP, GIF, AVIF or an SVG file) — the logo of the tool a link opens, a brand's own pictogram, a drawing exported from Figma. Chosen in a selector with a live preview of the row.
  • SVG made safe. Pasted markup is sanitised before it is stored and again before it is rendered: scripts, event handlers, foreign objects and external references are removed, it is sized by CSS, and it follows the text colour (active state included) unless the drawing brings its own colours.
  • Rename and re-icon what the code declares. Label, symbol, URL and badge of a registered page or resource can be overridden from the page; an empty field keeps what the class declares, and Release gives the item back to the code.
  • Live badges. Named resolvers registered on the plugin; an item is given one from a select. Resolved once per request.
  • Replaces the sidebar, and optionally the topbar, with its own Livewire components: brand block with tagline, type-to-filter box, monospace group markers. Every render hook of the stock sidebar and topbar is honoured in the same position.
  • Nothing disappears. Items the panel registers but the configuration has not placed stay visible under their native group. Rows whose page or resource is gone are skipped, not shown broken.
  • Filament decides who sees what. The plugin rearranges the navigation Filament already composed for the current user, so canAccess(), shouldRegisterNavigation() and cluster rules keep working. Role restrictions in the plugin are an extra layer on top.
  • Per panel. One configuration per panel id; the plugin can be registered on several panels of the same application.
  • Themeable. Every colour, size and font is a --kn-* custom property with a neutral fallback, in light and dark mode.
  • Explains itself. A How it works slide-over on the settings page walks through the flow and opens by itself on a panel with no configuration yet.

#Screenshots

Settings page — groups, Unsorted and Discovered, drag and drop between lists

Symbol selector — marker, icon, SVG or image, with a live preview of the row

Pasted SVG as the symbol of an item

Uploaded image as the symbol of an item — a product logo in the sidebar

Adding a custom link — URL, symbol, group and new tab

Sidebar — markers, icons, SVG and image symbols, badges and the active state

Sidebar in dark mode

Editing a group — label, symbol, collapsible, visibility and roles

Editing an item — label, URL, symbol, badge and roles

How it works — the help slide-over

#Requirements

  • PHP >= 8.4
  • Laravel >= 13.0
  • Filament >= 5.7

#Installation

This is a commercial package distributed through Anystack — it is not on public Packagist. Your license key is what authenticates the download.

1. Add the private repository to your project's composer.json:

{
    "repositories": [
        {
            "type": "composer",
            "url": "https://filament-navigator.composer.sh"
        }
    ]
}

2. Require the package:

composer require komma-softhouse/filament-navigator

Composer will prompt for authentication against filament-navigator.composer.sh:

  • Username: the email address your license is registered to.
  • Password: your license key. If your license policy requires a fingerprint, append it to the key separated by a colon — your-license-key:your-domain.com — using the fingerprint you entered when activating the license.

Answer yes when Composer offers to store the credentials (they go in auth.json — add that file to .gitignore). For CI, configure the same credentials as http-basic auth from your secrets instead:

composer config http-basic.filament-navigator.composer.sh your@email.com YOUR-LICENSE-KEY

3. Migrate and publish the assets:

php artisan migrate
php artisan filament:assets

The migrations are loaded from the package; publish them, or the config file, only if you need to edit them:

php artisan vendor:publish --tag=filament-navigator-migrations
php artisan vendor:publish --tag=filament-navigator-config

4. Register the plugin on your panel provider:

use Komma\Navigator\NavigatorPlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        // ...
        ->plugin(
            NavigatorPlugin::make()
                ->topbar()
                ->settingsPage()
                ->quickFilter()
                ->groupMarker(';')
                ->brandTagline('Admin')
                ->badges([
                    'tenants' => fn (): int => Tenant::query()->count(),
                ])
                ->authorizeSettingsUsing(fn (): bool => auth()->user()->hasRole('super-admin')),
        );
}

5. Import the navigation. Open the settings page (/{panel}/navigator) and press Import current navigation, or run:

php artisan navigator:snapshot admin

Until you do, the sidebar shows exactly the tree Filament builds — the plugin changes the look, not the structure.

#Configuration

The sidebar replacement is always on. Everything else ships disabled.

Method Getter Default Config key What it does
->topbar(bool $condition = true) hasTopbar() false topbar Replaces the panel topbar with the plugin's (brand block with tagline, sidebar controls, global search, notifications, user menu). Top navigation mode is not supported by the replacement topbar.
->settingsPage(bool $condition = true) hasSettingsPage() false settings_page Registers the Navigation page in the panel (slug navigator, group Settings).
->quickFilter(bool $condition = true) hasQuickFilter() false quick_filter Type-to-filter box at the top of the sidebar; filters the rendered items client-side, Esc clears.
->brandTagline(string | Closure | null $tagline) getBrandTagline() null brand_tagline Short monospace line under the logo, in the sidebar header and in the replacement topbar.
->groupMarker(?string $marker) getGroupMarker() '' group_marker Monospace character printed before every group label instead of an icon (;, , //).
->unsortedLabel(?string $label) getUnsortedLabel() 'Unsorted' unsorted_label Label of the trailing group that holds placed rows without a group. Passed through __().
->badges(array $resolvers) getBadges() [] Named closures. An item configured with one of these keys shows the returned value as its badge; null or '' hides it. Resolved once per request; a throwing resolver hides the badge.
->authorizeSettingsUsing(?Closure $callback) canManageSettings() any authenticated user Who may open the settings page.
->iconsDisk(?string $disk) getIconsDisk() 'public' icons.disk Filesystem disk for image symbols uploaded from the settings page. Must be publicly reachable.
->iconsDirectory(?string $directory) getIconsDirectory() 'navigator' icons.directory Directory on that disk.

Config file (config/filament-navigator.php):

Key Default What it does
connection null Database connection of the navigator tables (models and migration).
tables.groups / tables.items navigator_groups / navigator_items Table names. Change before the first migration.
cache_ttl 3600 Seconds the composed configuration of a panel stays cached. Every write flushes it; 0 disables the cache.
unsorted_label, topbar, settings_page, quick_filter, brand_tagline, group_marker see above Defaults for the fluent options. Environment variables: FILAMENT_NAVIGATOR_CONNECTION, FILAMENT_NAVIGATOR_CACHE_TTL, FILAMENT_NAVIGATOR_TOPBAR, FILAMENT_NAVIGATOR_SETTINGS_PAGE, FILAMENT_NAVIGATOR_QUICK_FILTER, FILAMENT_NAVIGATOR_BRAND_TAGLINE, FILAMENT_NAVIGATOR_GROUP_MARKER.
icons.disk / icons.directory public / navigator Where uploaded image symbols are stored. Environment variables: FILAMENT_NAVIGATOR_ICONS_DISK, FILAMENT_NAVIGATOR_ICONS_DIRECTORY.

#The settings page

A How it works header action opens a slide-over with the flow and the meaning of every row action; it opens by itself the first time, while the panel has no configuration. Two columns. On the left, the configured groups with their items; on the right, the Unsorted bucket and the Discovered list (items the panel registers that have no row yet). Everything is drag and drop, between lists included:

  • drag a discovered item into a group to place it;
  • drag a placed item back to Discovered to release it (custom links cannot be released, only deleted);
  • drag groups to reorder them.

Header actions: Import current navigation (imports every native group and item as rows, keeping existing rows), New group, Add link (a custom URL, optionally in a new tab), Reset (deletes the panel's configuration; the sidebar returns to what Filament builds).

Per group: edit (label, symbol, collapsible, collapsed by default, visible, roles) and delete (its items move to Unsorted). Per item: hide/show, edit (label, symbol, URL, badge, roles, new tab, visible — empty fields keep what the page or resource declares) and release/delete.

#Custom links

Add link creates a navigation item that no page or resource declares. It takes a label, a URL — a path of the application (/admin/reports) or a full address (https://status.example.com) —, a symbol, the group it goes in (or Unsorted) and whether it opens in a new tab. From then on it is a row like any other: drag it, edit it, give it a badge, restrict it to roles, hide it. It is highlighted as active while the current URL is its own. A custom link cannot be released, because there is no code to give it back to; it is deleted.

A registered page or resource accepts a URL too: filled in, the item keeps its place, access rules and active state and points somewhere else.

#Symbols: markers, icons, SVG, images

Every group and item — custom links included — has a Symbol, picked in its create or edit modal with a live preview of how the row will look. An icon name the application does not have is flagged in the preview and cannot be saved; one that stops existing later (an icon package removed) is ignored at render time, so a row never breaks the panel:

Choice Groups Items Stored as
Default the plugin's groupMarker() (or the native icon if the group has one) what the page or resource declares NULL
Marker any short text up to 16 characters (;, , $, //), monospace, in the accent colour marker column
Icon a Blade icon name available in the app (heroicon-o-home, phosphor-…) same icon column
SVG pasted markup, sanitised (scripts, event handlers, foreign objects and external references removed; sized by CSS; fill="currentColor" unless the drawing brings its own colours) same icon column, <svg…
Image PNG, JPG, WebP, GIF, AVIF or an SVG file up to 512 KB, uploaded to the icons disk and rendered as <img> at icon size same icon column, path on the disk

Rendering precedence for a group: its marker → its icon → the plugin's global marker.

Images keep their own colours in light and dark mode and do not react to the active state — good for product logos, SVG is better for menu icons. Uploads go to ->iconsDisk('public') / ->iconsDirectory('navigator') (config icons.disk / icons.directory); the disk must be publicly reachable.

Only items the current user can access are listed, because discovery reads the navigation Filament composed for that user: arrange the panel with an account that sees everything.

Roles are stored as an array of names and checked with hasAnyRole() on the panel's user model when that method exists (spatie/laravel-permission). Without it, role restrictions are ignored.

#How the composition works

  1. $panel->getNavigation() — Filament's own tree for the current user.
  2. Configured groups, in their order, with the rows placed in them. Rows whose key is not registered any more are skipped.
  3. Rows without a group → the Unsorted group.
  4. Registered items without a row → appended under their native group label, in native order.

With no rows at all for the panel the native tree is returned untouched, so installing the plugin changes the look but not the structure until you arrange it.

Item keys are what Filament assigns: the resource or page class for discovered items, the label for hand-made NavigationItem instances, custom:{slug}-{random} for links created from the page. Renaming a class orphans its row (it is skipped, never shown broken); release it from the page and place the item again.

#Artisan commands

php artisan navigator:snapshot {panel} [--fresh]   # import the native navigation (--fresh deletes the current rows first)
php artisan navigator:reset {panel} [--force]      # delete the configuration of a panel

The snapshot command runs without an authenticated user: pages and resources that gate navigation on the user register nothing there. Use the page action when that matters.

#Theming

The stylesheet reads these custom properties (defaults shown for light mode; .dark redefines the colours). Override them in the panel theme:

:root {
    --kn-bg: #ffffff;
    --kn-bg-elevated: color-mix(in srgb, var(--gray-50) 70%, #ffffff);
    --kn-fg: var(--gray-700);
    --kn-fg-strong: var(--gray-950);
    --kn-fg-muted: var(--gray-500);
    --kn-line: color-mix(in srgb, var(--gray-950) 8%, transparent);
    --kn-accent: var(--primary-600);
    --kn-accent-soft: color-mix(in srgb, var(--primary-500) 10%, transparent);
    --kn-hover: color-mix(in srgb, var(--gray-950) 5%, transparent);
    --kn-active-bg: color-mix(in srgb, var(--primary-500) 12%, transparent);
    --kn-active-fg: var(--gray-950);
    --kn-icon: var(--gray-400);
    --kn-icon-active: var(--primary-600);
    --kn-badge-bg: color-mix(in srgb, var(--primary-500) 16%, transparent);
    --kn-badge-fg: var(--primary-700);

    --kn-font: var(--font-family);
    --kn-mono: var(--mono-font-family);
    --kn-radius: 0.55rem;
    --kn-item-height: 2.35rem;
    --kn-group-gap: 1.1rem;
    --kn-label-size: 0.875rem;
    --kn-group-size: 0.66rem;
    --kn-group-tracking: 0.14em;
    --kn-marker-size: 0.9rem;
    --kn-pad-x: 0.9rem;
}

Class hooks, for anything the tokens do not cover: .kn-sidebar, .kn-header, .kn-brand, .kn-brand-tagline, .kn-filter, .kn-nav, .kn-group, .kn-group-head, .kn-group-marker, .kn-group-label, .kn-item, .kn-item-link, .kn-item-icon, .kn-item-label, .kn-item-badge-ctn, .kn-footer, .kn-topbar, .kn-topbar-brand, .kn-topbar-end. Active states: .kn-item-active, .kn-item-parent-active, .kn-group-active, .kn-collapsed.

All render hooks of the stock sidebar and topbar (SIDEBAR_START, SIDEBAR_LOGO_BEFORE/AFTER, SIDEBAR_NAV_START/END, SIDEBAR_FOOTER, TOPBAR_START/END, TOPBAR_LOGO_BEFORE/AFTER, GLOBAL_SEARCH_BEFORE/AFTER) are honoured in the same positions.

#Dark mode and translations

Every surface the plugin renders — sidebar, topbar, settings page and the help slide-over — follows Filament's own light/dark toggle with no configuration; .dark redefines the --kn-* colour tokens.

Strings are English literals wrapped in __(); a Spanish translation ships in resources/lang/es.json, and the keys resolve against your own application's lang/{locale}.json too. Publish to add a language:

php artisan vendor:publish --tag=filament-navigator-translations

#Testing

composer test

#Changelog

Please see CHANGELOG for more information on what has changed recently.

#Support and community

The plugin's source is private. Everything public lives in the docs repository:

#Security Vulnerabilities

Never in a public issue or discussion. Please review our security policy — a private advisory on the docs repository, or security@kommasofthouse.com.

#Credits

#License

This is commercial software. Please see License File for the full terms.

The author

Komma SoftHouse avatar Author: Komma SoftHouse

Komma SoftHouse builds Laravel and Filament software — point-of-sale, ERPs, and the multi-tenant SaaS platform behind them. The plugins it publishes are pieces of that work, released once they have proven themselves in production: Spanish fiscal compliance, tenancy infrastructure, and whatever the next product turns out to need.

Plugins
5
Stars
5

From the same author

Tenancy Suite plugin thumbnail

Tenancy Suite

Database-per-tenant multi-tenancy on stancl/tenancy: one identity across every workspace, invitations, custom domains verified by DNS, backups and restore, health checks with per-check repairs, async provisioning, and a pool of database servers.

Komma SoftHouse avatar Author: Komma SoftHouse
1 star
Tag: Panels Tag: Panel Authorization More tags: +2
Dark mode ready Multilingual support
$129.00
Buy now
Verifactu plugin thumbnail

Verifactu

VERI*FACTU / RRSIF and TicketBAI compliant fiscal engine for Filament 5, covering all four Spanish fiscal regimes: chained fiscal records, AEAT and foral submission, XAdES signing, the full document lifecycle, the received side of the ledger, FACe/FACeB2B, and state and foral tax report drafts.

Komma SoftHouse avatar Author: Komma SoftHouse
1 star
Tag: Panels
Dark mode ready Multilingual support
€299.00
Buy now
Eesti Billing plugin thumbnail

Eesti Billing

Invoicing for companies established in Estonia: numbered document cycle, VAT decided by customer with VIES proof, viitenumber, KMD/VD/OSS files for e-MTA, e-invoices (EN 16931, e-arve), ID-kaart / Smart-ID / Mobile-ID signing, thermal receipts and a service desk.

Komma SoftHouse avatar Author: Komma SoftHouse
1 star
Recently added: New Tag: Panels More tags: +2
Dark mode ready Multilingual support
$199.00
Buy now
BTCPay plugin thumbnail

BTCPay

A complete Bitcoin and Lightning payment system on your own BTCPay Server, run from a Filament 5.x panel. No intermediary, no custodian, no fees beyond the network's: the plugin talks to the server you run, and everything a shop does with bitcoin — invoices, refunds, the wallet, the Lightning node, payment requests, payouts, a pay button, a point of sale, reports, several stores — happens in the panel, never in BTCPay's own UI.

Komma SoftHouse avatar Author: Komma SoftHouse
1 star
Recently added: New Tag: Action More tags: +3
Dark mode ready Multilingual support
$149.00
Buy now