bisual/laravel-shortcuts
bisual/laravel-shortcuts is a lightweight Laravel package that gives you handy shortcuts and helper utilities for everyday development tasks. It reduces boilerplate, keeps your code cleaner and more consistent, and helps you build features faster with less repetitive code.
bisual/laravel-shortcuts lets you declare keyboard shortcuts in PHP and have them wired up in the browser, so you are not scattering addEventListener('keydown', …) calls across your Blade views.
Minimal path in:
composer require bisual/laravel-shortcuts
php artisan vendor:publish --provider="Bisual\Shortcuts\ShortcutsServiceProvider"
Then, in order:
config/shortcuts.php — this is the file you will actually live in. It holds the shortcut registry (key, modifiers, label, and the action it fires). Read it before anything else; it tells you the shape the package expects.README.md in vendor/bisual/laravel-shortcuts — the published config is version-pinned at install time, so the README is the only place that reflects the release you actually have.src/ and resources/js/ — find the Blade component/directive and the JS entry point. Ten minutes here saves an hour of guessing how events are dispatched.php artisan vendor:publish --tag=shortcuts-assets (if the tag exists) and confirm the JS is registered in your Vite/app.js bundle. A published-but-not-imported asset is the single most common "it does nothing" cause.First use case worth shipping: a Cmd/Ctrl + K shortcut that opens your existing search field or a command palette. It is low-risk, immediately visible to users, and exercises the full path — registry → Blade render → JS binding → your handler.
On v1.5.7 specifically: the changelog is a single branch merge (BP2310 into main) with no described API changes. Treat it as a maintenance bump. composer update bisual/laravel-shortcuts is the only action required; composer outdated will confirm the constraint resolves.
Central registry over scattered declarations. Keep shortcut definitions in config/shortcuts.php (or a dedicated ShortcutsServiceProvider if you need per-tenant/permission variation). Registering them inline in individual views means the same key gets bound twice on pages that compose multiple components, and the last registration silently wins.
Blade-driven hydration. Render the shortcut set once, near the root layout, rather than per-component:
{{-- layouts/app.blade.php --}}
<x-shortcuts />
…then let your page-specific JS listen for the resulting event. One hydration point means one place to debug.
Scope your shortcuts. Modal, code editor, and command-palette contexts need to suspend global shortcuts — otherwise Cmd+K opens the palette while the palette is already open, or typing g in an editor navigates away. Prefer an explicit scope/group attribute in the registry plus an enable/disable call from your JS when a modal mounts, over ad-hoc if (document.activeElement.tagName === 'INPUT') checks.
Livewire integration. Shortcut actions that mutate server state should dispatch a Livewire event or call a component method, not manipulate the DOM directly. The pattern that stays maintainable:
// Livewire component
#[On('shortcut:open-search')]
public function openSearch(): void { $this->showSearch = true; }
Keep the browser-side handler a thin translator: key press → named event → component method. Business logic stays testable in PHP.
Feature-test the registry, browser-test the binding. Unit tests can assert your config/provider produces the expected shortcut definitions and that gates/permissions filter correctly. The actual keypress behaviour needs a browser test (Dusk/Playwright) — asserting keydown wiring from PHPUnit is not worth the mocking effort.
Register idempotently. If you bind listeners in Alpine init() or on livewire:navigated, guard against double-binding. A WeakSet of bound elements or a single delegated listener on document (with a lookup by event.key) is far more robust than per-element listeners that leak on re-render.
Cmd vs Ctrl yourself. Most registries store a generic "mod" modifier and resolve to metaKey on macOS and ctrlKey elsewhere. Test both paths — a shortcut that only works on the author's Mac will pass review and fail for half your users.Cmd+W, Cmd+T, Cmd+R, Cmd+1..9 are not reliably interceptable, and intercepting the ones that are is user-hostile. Stick to Cmd/Ctrl+K, Cmd/Ctrl+Enter, /, ?, g-then-key sequences.input, textarea, select, [contenteditable]. A single-letter shortcut that hijacks typing in a comment box is the classic bug. Gate on event.target.closest('input, textarea, select, [contenteditable]').x-if all replace DOM nodes. Delegated document-level listeners survive morphs; element-level listeners do not. If shortcuts work on hard reload but die after wire:navigate, this is why.vendor:publish --force, run a fresh npm run build. Stale hashed JS pointing at an old registry shape produces silently failing shortcuts with no console error.php artisan config:cache can freeze a stale set. Verify on a cached-config environment (your staging/production) before assuming your provider logic is wrong.compare/v1.5.6...v1.5.7) rather than the release text, and pin to ~1.5.0 so an ambiguous patch can't surprise production. If a shortcut regresses after an update, diff the published config against the new stub first — package config stubs change shape more often than the source does.How can I help you explore Laravel packages today?