Command palette · Open source
Laravel Ninja Keys
A Cmd+K / Ctrl+K command palette for Laravel, with the actions defined in PHP.
What it solves
Adding the ninja-keys command palette to a Laravel app by hand means writing a script per layout, building the action list in JavaScript, and tracking which actions each user is allowed to see.
You register actions in PHP, hide the ones a user may not use with your Gate abilities, and render the palette with <x-ninja-keys />. ninja-keys 1.2.2 is bundled and self-hosted, so there is no JavaScript to write and no npm build step.
- Actions built in PHP, with route() and href() for navigation
- ->can() runs Gate abilities on the server, so hidden actions never reach the browser
- define() callbacks run at render time with the current user and request
- Submenus from parent and children ids, or from nested arrays
- Works across Livewire wire:navigate without duplicate shortcuts
- ninja-keys 1.2.2 bundled and self-hosted, with fixes for three upstream bugs
Install
Requires PHP 8.3+ and Laravel 12 and 13.
composer require amjadiqbal/laravel-ninja-keys
Usage
// app/Providers/AppServiceProvider.php
use AmjadIqbal\NinjaKeys\Facades\NinjaKeys;
use AmjadIqbal\NinjaKeys\Manager;
NinjaKeys::define(function (Manager $palette) {
$palette->addAction('dashboard')->title('Dashboard')->mdIcon('dashboard')->route('dashboard')->hotkey('alt+1');
$palette->addAction('users')->title('Manage users')->mdIcon('group')->route('users.index')->can('manage-users');
});
// In your layout, before </body>: <x-ninja-keys />
Setup
The service provider and the NinjaKeys facade are auto-discovered. The JavaScript bundle is published to public/vendor/ninja-keys on composer update through Laravel's laravel-assets step. If your app does not run that step, publish it once. Until it is published, the palette loads ninja-keys from jsDelivr.
- 1 composer require amjadiqbal/laravel-ninja-keys
- 2 php artisan vendor:publish --tag=ninja-keys-assets
Render the palette
Put the component once in your main layout, before </body>. Any element with data-ninja-keys-open opens the palette on click, optionally straight into a submenu.
<x-ninja-keys />
{{-- or as a directive --}}
@ninjaKeys
<button data-ninja-keys-open>Search <kbd>⌘K</kbd></button>
<button data-ninja-keys-open="theme">Change theme…</button>
Register actions
Register actions in a controller for page-specific actions, or with define() in a service provider for the global ones. has(), forget() and clear() let a page remove or replace global actions.
NinjaKeys::addAction('new-invoice')
->title('New invoice')
->section('Billing')
->mdIcon('receipt_long')
->keywords('bill charge create')
->hotkey('alt+n')
->route('invoices.create');
Only show what the user may do
Hidden actions and their sub-actions are removed on the server; they never appear in the page source.
Gate::define('manage-users', fn (User $user) => $user->is_admin);
NinjaKeys::addAction('users')->title('Users')->can('manage-users')->children(['invite']);
NinjaKeys::addAction('invite')->title('Invite a user')->parent('users')->route('users.invite');
Configuration
Publish the config with php artisan vendor:publish --tag=ninja-keys-config.
- script: local (the bundled file), cdn (jsDelivr) or null (you import ninja-keys with Vite).
- theme: auto, light or dark.
- openHotkey: cmd+k,ctrl+k by default.
- livewire_navigate: make href() and route() actions use Livewire.navigate().
- onOpen, onChange, onSelected: names of global functions to call.
- Both scripts carry the CSP nonce when you use Vite::useCspNonce().
Hire me
Need this built into your app, or something custom?
I wrote Laravel Ninja Keys. I can wire it into your Laravel app, extend it for your case, or build the feature around it. Tell me what you need and you'll get a plan and a quote, free.
Support
Found a bug or want a feature? Open an issue on GitHub. For help adding it to your own project, use the quote form above.
More Laravel packages
All packages
Laravel Driver.js
Build Driver.js product tours in PHP and render them with one Blade component.
Laravel Sonner
Sonner toast notifications for Laravel, sent from PHP and shown without React.
Laravel SweetAlert2
SweetAlert2 popups, toasts and confirm dialogs from Laravel controllers, Livewire and Alpine.
Laravel Grid.js
Turn any Eloquent query into a searchable, sortable, paginated Grid.js data table with one fluent PHP call.
Laralink
Work on a Composer package inside the Laravel app that uses it, then switch back to the Packagist release.
Refresher
A drop-in replacement for Laravel's RefreshDatabase that restores a cached snapshot of your test database instead of running migrate:fresh.
Kiln
Artisan commands and an optional signed HTTP route to clear, warm and inspect OPcache when you deploy.
Laravel Media Viewer
Show private PDFs, video and audio from any Laravel disk without making the files public.
Laravel Swiper
Swiper sliders, carousels and image galleries for Laravel as Blade components.
Laravel MySQL Advisor
Read-only health checks for the MySQL or MariaDB database behind your Laravel app, with the SQL and the Laravel migration to fix a problem wherever a fix applies.
Laravel Webhook Console
A dashboard and replay tool for the webhooks spatie/laravel-webhook-client stores in your Laravel app.