Command Palette
Command Palette component.
Command Palette, Customization Blocks
<x-command-palette id="search" :request="route('api.users')" select="label:name|value:id" /> <x-button x-on:click="$tsui.open.commandPalette('search')"> Open Command Palette</x-button>
When you press enter to select an option, the component dispatches a select event with the selected option's value in the event.detail.value property. Continue reading to learn about all the ways to interact with the component and handle selections.
The command palette opens when the user presses the configured keyboard shortcut. The default is Ctrl + K , but you can change it inline or globally in the configuration file using dot notation: ctrl.k , ctrl.shift.p , meta.k , or even inline using the shortcut attribute with the same dot notation.
The request attribute defines where the component fetches search results from. You can use a simple URL string or a Laravel route name:
<!-- Simple URL string --><x-command-palette request="/api/search" /> <!-- Using a route name --><x-command-palette request="api.users" /> <!-- Using full route path --><x-command-palette :request="route('api.users')" />
For more control, pass an array with url , method , and params keys:
<!-- Array with url, method, and params --><x-command-palette :request="[ 'url' => '/api/search', 'method' => 'post', 'params' => ['category' => 'users'],]" />
The select attribute maps your API response fields to the component's internal structure. The format is exactly the same to the select.styled component:
<x-command-palette id="users" request="/api/users" select="label:name|value:id|description:email|image:avatar" /> <x-button x-on:click="$tsui.open.commandPalette('users')"> Search Users</x-button>
An option to disable specific items.
The API response should response as it to disable an item:
[ { "name": "Active User", "id": 1 }, { "name": "Inactive User", "id": 2, "disabled": true }]
By default, the component preserves previous search results when the palette is reopened. Use the recycle attribute to control this behavior:
<!-- Preserves previous results when reopening (default: true) --><x-command-palette request="/api/search" /> <!-- Clears results every time the palette opens inline --><x-command-palette request="/api/search" :recycle="false" />
You can also control it globally in the configuration file.
<!-- Available keys: search, empty, navigate, select, close --><x-command-palette request="/api/search" :placeholders="[ 'search' => 'Type to search...', 'empty' => 'Nothing found.', ]" />
<x-command-palette id="search" request="/api/search"> <x-slot:empty> <div class="flex flex-col items-center gap-2 p-8"> <x-icon name="magnifying-glass" class="h-8 w-8 text-gray-400" /> <p class="text-sm text-gray-500">No results match your search.</p> </div> </x-slot:empty></x-command-palette> <x-button x-on:click="$tsui.open.commandPalette('search')"> Open Command Palette</x-button>
You have three different ways to interact with an item selection. The simplest way is to set x-on:select to handle the selection with component scope. When present, this option has the highest priority and suppresses both the actionable and global events.
<x-command-palette id="search" request="/api/users" x-on:select="console($event.detail.label)" /> <x-button x-on:click="$tsui.open.commandPalette('search')"> Open Command Palette</x-button>
Since you might want to use the component globally, like in a layout file, you can interact with item selection in two other ways. You can configure an invocable PHP class in the configuration file to handle selections on the server side. This way, selecting an item will go through an internal TallStackUI route to handle the action of creating the instance of your class and invoking it through the Laravel container. The internal TallStackUI endpoint uses Laravel-signed URLs for added security.
// ... 'command-palette' => [ Components\CommandPalette\Component::class, /* |---------------------------------------------------------------------- | Command Palette Settings |---------------------------------------------------------------------- | | actionable: the callable class for handling item selection (e.g., App\Support\GlobalSearch::class). | request: the data source for the command palette. | select: the default field mapping of the results (e.g., 'label:name|value:id|description:email|image:avatar'). | z-index: controls the default z-index. | blur: enables the background blur effect (Allowed: false, sm, md, lg, xl). | overflow: avoids hiding the overflow, allowing the scroll of the page. | shortcut: keyboard shortcut to toggle the palette (e.g., 'ctrl.k', 'ctrl.shift.p'). | recycle: when true, preserves previous results when reopening the palette. | elements: when true, shows the keyboard hints in the footer. | scrollbar: when true, applies a custom minimal scrollbar to the results list. | centered: when true, centers the palette vertically on mobile with fully rounded corners. | overlay: when false, hides the dimmed background overlay rendered behind the palette. */ [ 'actionable' => App\Actions\CommandPaletteAction::class, 'request' => null, 'select' => null, 'z-index' => 'z-50', 'blur' => false, 'overflow' => false, 'shortcut' => 'ctrl.k', 'recycle' => true, 'elements' => true, 'scrollbar' => true, 'centered' => false, 'overlay' => true, ],], // ...
The class receives an ItemSelected value object and must return a Callback response:
use TallStackUi\Support\CommandPalette\Callback;use TallStackUi\Support\CommandPalette\ItemSelected; class CommandPaletteAction{ public function __invoke(ItemSelected $selected): Callback { return Callback::redirect("/users/{$selected->value}"); }}
The ItemSelected object provides access to all selection data:
// ItemSelected properties: $selected->search; // string — the search term$selected->label; // mixed — option label$selected->value; // mixed — option value$selected->description; // ?string — optional description$selected->image; // ?string — optional image URL$selected->icon; // ?string — optional icon HTML$selected->additional; // array — extra fields from the API
The Callback class offers two response types: redirect the user to a page (internal ou external) or you can also dispatch a browser event:
namespace App\Actions; use TallStackUi\Support\CommandPalette\Callback;use TallStackUi\Support\CommandPalette\ItemSelected; class CommandPaletteAction{ public function __invoke(ItemSelected $selected): Callback { // Redirect to an internal page return Callback::redirect("/users/{$selected->value}"); // Redirect to an external URL (opens in new tab) return Callback::redirect('https://example.com')->external(); // Redirect using Livewire.navigate (SPA-style navigation) return Callback::redirect('/dashboard')->navigate(); // Dispatch a browser event return Callback::event('user-selected'); // Dispatch a browser event with parameters return Callback::event('user-selected')->with(['id' => $selected->value]); }}
<!-- Inline lifecycle events --><x-command-palette id="search" request="/api/search" x-on:open="console.log('opened')" x-on:close="console.log('closed')" /> <!-- Global lifecycle events (event name includes the id) --><div x-on:command-palette:search:select.window="console.log($event.detail)" x-on:command-palette:search:open.window="console.log('opened')" x-on:command-palette:search:close.window="console.log('closed')"> <x-command-palette id="search" request="/api/search" /></div>
Helpers to open and close the command palette using AlpineJS.
<x-command-palette id="search" request="/api/search" /> <!-- Open by id --><x-button x-on:click="$tsui.open.commandPalette('search')"> Open</x-button> <!-- Close by id --><x-button x-on:click="$tsui.close.commandPalette('search')"> Close</x-button>
By default, the command palette is aligned to the bottom of the screen on mobile devices. You can change this behavior in the configuration file using the centered configuration. When set to true, the command palette will be centered on mobile devices.
By default, the command palette renders a dimmed overlay behind itself to focus attention on the search. Pass :overlay="false" to skip the overlay and let the palette float above the page without darkening the surrounding UI:
<!-- Default: dimmed overlay rendered behind the palette --><x-command-palette id="default" :request="route('api.users')" /> <!-- Opt-out: palette floats with no background dimming --><x-command-palette id="floating" :request="route('api.users')" :overlay="false" />
You can also flip the default globally in the configuration file via the overlay key.