takashato/filament-spotlight
A Filament plugin that adds a Spotlight-style command palette to your admin panel, letting users quickly search records and jump between resources, pages, and actions from a single keyboard-driven overlay.
This is a first public release (v0.1.0) of a Spotlight-style command palette for Filament v5 panels. Treat it as an early-adopter package: the feature surface is already broad (pluggable sources, recents, a11y, localization), but the API has no stability guarantee yet.
Minimal path to a working palette:
composer require takashato/filament-spotlight:^0.1.SpotlightPlugin on each panel you want the palette in (typically in your PanelProvider's panel() method, alongside your other plugins).php artisan migrate, then hit Cmd/Ctrl+K in the panel.Where to look first:
config/spotlight.php — the fastest way to understand what is tunable (source registration, recents cap, keyboard shortcut, locale behaviour).SpotlightSource contract and Result DTO — these define everything you will extend.FilamentResourceSource — the reference implementation. Read it before writing your own source; it establishes the conventions for query handling, authorization, and handler construction.First real use case: navigation and record-jumping. The built-ins (FilamentResourceSource, NavigationSource) give you global search across resources plus panel navigation with no custom code. Once that is live, the Tab-activated per-row Filament actions in the resource source are the feature that typically earns adoption — it turns "find the record" and "do the thing to the record" into one keyboard flow instead of two.
Multi-panel registration. Register the plugin per panel rather than globally. Each panel has its own navigation and resource set, so a shared source list will surface results a user cannot act on. If you run admin + tenant panels, configure sources per panel.
Writing a custom source. Implement SpotlightSource, return a collection of Result objects, and register it on the plugin. The practical pattern:
Choosing a Handler. The factory covers four shapes, and picking the right one is most of the integration work:
url — for internal navigation. Subject to same-origin validation, so use relative paths or same-host URLs.event — for dispatching a browser/Livewire/Alpine event. Payloads are restricted to scalars.modal — for opening a Filament action or modal from a result.callback — for arbitrary server-side or class-level logic that does not fit the above.Recents as a UX layer, not a security layer. Per-user recents with LRU eviction and permission re-validation means the palette filters entries the user can no longer access. That is a good default, but it is a display guarantee — still enforce policies at the handler destination. A stale URL that survives re-validation because the policy changed shape (rather than the permission being revoked) will still resolve.
Localization and RTL. en and vi ship out of the box. If you support other locales, plan to add translations early rather than shipping a partially localized palette; the combobox labels and the mobile close button are the strings that matter for the WCAG claims to hold in your language.
Testing. Assert on sources in isolation (given a query and a user, which Results come back) rather than driving the whole palette through the browser. The handler validation layer is worth a dedicated test: it is the component most likely to silently drop a result you expected to see.
^0.1 and read the changelog before every minor bump. Pre-1.0 releases from a single maintainer routinely ship breaking changes marked as minor.event or callback rather than fighting the validator.event payloads. Flatten, or pass an identifier and resolve the rest on the receiving side.Cmd/Ctrl+K collides. It conflicts with browser-level shortcuts in some contexts, with other palette packages, and — depending on your Filament version — with Filament's own global search modal. Bind one thing to that chord per panel.Tab for row actions is unconventional. It diverges from the browser's normal tab-navigation contract. It works, but it will surprise users who tab out of the input expecting focus to move. Consider documenting it in your own onboarding rather than relying on discovery.LIMIT, indexed columns). This is the most likely place to introduce a latency regression.callback handlers are serialized into the palette payload, closures capturing non-serializable state will fail. Prefer class strings or static methods until you have confirmed the mechanism in source.SpotlightSource contract (custom result types), the Handler factory (the natural place to want a fifth handler type), and config/spotlight.php (where a source registry likely lives). These three are where you will spend your integration effort.How can I help you explore Laravel packages today?