vitisstudio/filament-hover-sidebar
A Filament plugin that adds a hover-expandable sidebar to your admin panel, letting navigation stay compact until users hover to reveal full labels and menus. Keeps interfaces clean while improving access to resources, ready to install and configure in any Filament app.
vitisstudio/filament-hover-sidebar turns Filament's desktop sidebar into a collapsed icon rail that expands on hover (mouse) or press (touch), giving the panel back its horizontal space without forcing users into core's collapse toggle.
composer require vitisstudio/filament-hover-sidebar
Register the plugin on the panel(s) that should get the rail:
// app/Providers/Filament/AdminPanelProvider.php
use VitisStudio\FilamentHoverSidebar\FilamentHoverSidebarPlugin;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->plugin(FilamentHoverSidebarPlugin::make());
}
Then make sure the plugin's CSS/JS actually ships to the browser:
php artisan filament:assets # or vendor:publish --tag=filament-hover-sidebar-*
php artisan optimize:clear
Where to look first: composer.json for the Filament major-version constraint (this is a 0.1.x package — pin it and read the constraint before upgrading), then the plugin class for any make()/config fluent methods, then the published CSS/JS if you need to override the breakpoint or pointer logic.
First use case: a resource-heavy admin panel (10+ nav items, long labels) on a 1280–1920px desktop. Users keep the rail permanently collapsed, hover to peek at labels, and click through. Measure this against ->sidebarCollapsibleOnDesktop() in core — the rail is the "peek instead of toggle" variant of the same idea, and running both invites conflicting chevrons.
Treat it as a per-panel decision, not a global one. Register the plugin only on dense back-office panels. A customer-facing panel with 4 nav items gains nothing and inherits the touch-tap semantics below.
Upgrade path from v0.1.2 → v0.1.3 is safe but user-visible. There is no API or config change, but the gating condition changed: the rail is now min-width: 1024px instead of (hover: hover) and (pointer: fine). Two consequences worth a ticket of their own:
Test the four input classes explicitly — they now behave differently on purpose:
| Input | ≥1024px | <1024px |
|---|---|---|
| Mouse | delayed hover peek | core Filament |
| Touch | press to expand, second press navigates | core Filament |
| Pen | press to expand | core Filament |
| Hybrid laptop (mouse + touchscreen) | per-event pointerType — same session can do both |
core Filament |
The hybrid case is the one to smoke-test, since behaviour is decided per pointerdown, not per device.
Instrument your nav clicks after enabling, not before. The expand-first rule is enforced by a capture-phase click listener on the sidebar that calls stopPropagation(). Anything bound on the anchor itself — a global analytics listener, a custom wire:click, an Alpine @click — will not fire for the tap that expands the rail. If nav click-through is a KPI, wire your tracking on the navigation/Livewire event instead of the DOM click.
Pair it with wire:navigate/Alpine navigate knowingly. The package deliberately sits above Alpine's navigate plugin in the capture phase. That is what makes "first press expands" work, but it also means your own capture-phase listeners registered after the plugin's will lose the event.
Debugging the CSS layer: the rail styles are plain CSS gated on a media query. If you maintain a custom Filament theme, verify the plugin's stylesheet is imported before your overrides and that you haven't re-added a (pointer: fine) gate in your own theme — the most likely cause of "the touch fix didn't apply" is a stale published asset, not a logic bug.
php artisan filament:assets and php artisan optimize:clear (and view:clear if you've published views) before filing a bug — a browser-cached old stylesheet reproduces the exact pre-fix bug.detail === 0). focusin has already expanded the rail, so Enter/Space goes straight through. Note that some synthetic/programmatic .click() calls also report detail === 0 in browsers, so scripted clicks bypass the expand-first guard — fine for tests, worth knowing if you drive nav from JS.pointerdown elsewhere in the document, or on navigation. Don't fight this with your own outside-click handler; you'll just get double-collapse flicker.preventDefault() on pointerdown will not cancel the following click. If you're writing a companion plugin that intercepts rail presses, you need a capture-phase click listener plus stopPropagation() — the same trick this release uses. preventDefault() alone silently does nothing here.composer.json before bumping. At 0.1.x there is no semver promise; pin exact versions in composer.lock, upgrade deliberately, and re-run your touch + mouse + keyboard checklist each time.vendor/.How can I help you explore Laravel packages today?