The Keyboard Shortcut Gap in Laravel Applications
There is a clear signal in the most beloved developer tools: they all have excellent keyboard support. GitHub responds to T, G D, G I, ?, and dozens of other shortcuts. Linear uses ⌘K for everything. Notion has a comprehensive keyboard overlay accessible at any time. These are not just nice-to-haves — they are signals of product quality that power users recognise immediately.
Laravel Blade applications have historically lagged here. Not because keyboard shortcuts are technically difficult to add, but because:
- There is no standard Laravel convention for shortcut registration
- Keyboard event listeners scattered across JavaScript files are hard to maintain
- There is no discoverability UI — users cannot see what shortcuts are available
- Each shortcut conflict requires manual resolution
The ninja-keys web component solves problems 3 and 4 beautifully: it provides a searchable command overlay that makes every registered shortcut discoverable. Laravel Ninja Keys solves problems 1 and 2 by moving shortcut registration into PHP.
Installing Laravel Ninja Keys
composer require amjadiqbal/laravel-ninja-keys
Publish the configuration:
php artisan vendor:publish --provider="AmjadIqbal\LaravelNinjaKeys\NinjaKeysServiceProvider" --tag="config"
Add the directive to your main layout, just before </body>:
@ninjakeys
That is the minimum viable setup. The overlay appears when the user presses / (configurable) and displays all registered shortcuts.
Registering Shortcuts
The recommended pattern is to register shortcuts in a service provider. This ensures they are available across all pages:
use AmjadIqbal\LaravelNinjaKeys\Facades\NinjaKeys;
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
NinjaKeys::section('Navigation')
->add('Dashboard', route('dashboard'), icon: 'heroicon-o-home', keys: ['g d'])
->add('Projects', route('projects.index'), icon: 'heroicon-o-folder', keys: ['g p'])
->add('Blog', route('blog.index'), icon: 'heroicon-o-document-text', keys: ['g b'])
->add('Contact', route('contact.show'), icon: 'heroicon-o-envelope', keys: ['g c']);
NinjaKeys::section('Actions')
->add('New Project', route('projects.create'), icon: 'heroicon-o-plus', keys: ['n p'])
->add('Search', '#search-input', icon: 'heroicon-o-magnifying-glass', keys: ['/'], action: 'focus');
}
}
Page-Specific Shortcuts
For shortcuts that only make sense on a specific page, register them in the controller before returning the view:
class ProjectController extends Controller
{
public function show(Project $project): View
{
NinjaKeys::section('Project Actions')
->add('Edit Project', route('projects.edit', $project), icon: 'heroicon-o-pencil', keys: ['e'])
->add('Delete Project', '#delete-project-form', icon: 'heroicon-o-trash', keys: ['d'], action: 'submit');
return view('projects.show', compact('project'));
}
}
How the Web Component Integration Works
The @ninjakeys Blade directive outputs two things:
- The ninja-keys web component JavaScript (from the configured CDN or asset path)
- A
<ninja-keys>custom element with the registered shortcuts serialised as adataattribute
<!-- Simplified output of @ninjakeys -->
<script type="module" src="https://cdn.jsdelivr.net/npm/ninja-keys"></script>
<ninja-keys>
<script slot="hotkeys">
const hotkeys = [
{ id: "go-home", title: "Dashboard", section: "Navigation", hotkey: "g d", handler: () => window.location.href = "/" },
{ id: "go-projects", title: "Projects", section: "Navigation", hotkey: "g p", handler: () => window.location.href = "/projects" },
// ...
];
</script>
</ninja-keys>
The ninja-keys web component renders entirely via the Shadow DOM, so it does not conflict with your application's CSS. The overlay appearance is controlled by CSS custom properties that you can override in your stylesheet.
Theming to Match Your Application
ninja-keys {
--ninja-accent-color: #22d3ee; /* Match your app's primary colour */
--ninja-background: #18181b; /* Dark zinc to match a dark theme */
--ninja-text-color: #d4d4d8;
--ninja-secondary-background: #09090b;
--ninja-border-radius: 0.75rem;
--ninja-icon-color: #71717a;
}
Accessibility Considerations
The ninja-keys web component ships with built-in ARIA support:
- The overlay is a
role="dialog"witharia-modal="true" - The search input is
aria-label-ed - Results are a
role="listbox"withrole="option"items - Focus is trapped within the overlay when open and restored to the trigger element when closed
For keyboard-only users, the overlay can be opened with the Tab key if the trigger element is in the focus order.
GitHub Repository
Full documentation and configuration reference on GitHub.
Conclusion
Adding keyboard shortcuts to a Laravel application used to mean writing and maintaining scattered JavaScript event listeners with no discoverability story. Laravel Ninja Keys gives you a PHP-first shortcut registry, a searchable command overlay, and a production-ready web component integration in under ten minutes. If your application serves power users, this is the feature they will notice and appreciate.