Command
The ⌘K menu. Type to filter, arrow keys to move, Enter to run. Filtering happens in the
PetalCommand
hook so keystrokes never wait on the server, and every item is a real link or button - so navigate,
patch
and any phx-*
binding work exactly as they do everywhere else in LiveView. The markup follows the WAI-ARIA
combobox pattern, so it's keyboard and screen-reader friendly out of the box.
Inline palette
A palette panel you drop into a page, sidebar or picker. Type to filter; arrow keys move, Enter runs.
<div class="w-full max-w-md mx-auto">
<.command
id="showcase-command"
loop
class="border border-gray-200 shadow-xs dark:border-white/15"
>
<.command_input placeholder="Type a command or search..." />
<.command_list>
<.command_empty>No results found.</.command_empty>
<.command_group heading="Suggestions">
<.command_item keywords={["date", "schedule"]}>
<.icon name="hero-calendar" /> Calendar
</.command_item>
<.command_item keywords={["smile"]}>
<.icon name="hero-face-smile" /> Search emoji
</.command_item>
<.command_item disabled>
<.icon name="hero-calculator" /> Calculator
</.command_item>
</.command_group>
<.command_separator />
<.command_group heading="Settings">
<.command_item keywords={["account", "user"]}>
<.icon name="hero-user" /> Profile
<.command_shortcut>⌘P</.command_shortcut>
</.command_item>
<.command_item keywords={["payment", "card"]}>
<.icon name="hero-credit-card" /> Billing
<.command_shortcut>⌘B</.command_shortcut>
</.command_item>
</.command_group>
</.command_list>
</.command>
</div>
The ⌘K dialog
The same palette in a native <dialog> - top layer, focus trap and Escape for free. Open it from any element.
<div class="flex flex-col items-center gap-3">
<.button
color="gray"
variant="outline"
phx-click={PetalComponents.Command.open_command("showcase-cmdk")}
>
<.icon name="hero-magnifying-glass" class="w-4 h-4 mr-1" /> Open command palette
</.button>
<.command_dialog id="showcase-cmdk" shortcut="">
<.command_input placeholder="Search components and actions..." />
<.command_list>
<.command_empty>Nothing matches. Try a component name.</.command_empty>
<.command_group heading="Navigation">
<.command_item keywords={["home"]}>
<.icon name="hero-home" /> Overview
</.command_item>
<.command_item keywords={["ui", "components"]}>
<.icon name="hero-squares-2x2" /> Components
</.command_item>
<.command_item keywords={["price", "plans"]}>
<.icon name="hero-credit-card" /> Pricing
</.command_item>
</.command_group>
</.command_list>
</.command_dialog>
</div>
Filtering and keywords
The hook matches the visible label plus any keywords
you add, so "schedule" can find Calendar
even though the word never appears on screen. Items are hidden, never reordered - the server
owns DOM order, which keeps everything safe under LiveView patches. Pass loop
to wrap the arrow keys from the last item back to the first.
Properties
The two shells - command/1
and command_dialog/1
- plus the command_item/1
each row is built from. The pieces in between (command_input/1, command_list/1, command_empty/1, command_group/1, command_separator/1, command_shortcut/1) take the obvious props.
| Attribute | Type | Default | Description |
|---|---|---|---|
class
|
any |
nil
|
extra classes for the palette panel |
id*
|
string |
unique id; the PetalCommand hook mounts here | |
loop
|
boolean |
false
|
arrow keys wrap from the last item to the first and back |
rest
|
global |
||
:inner_block
slot
|
slot |
| Attribute | Type | Default | Description |
|---|---|---|---|
class
|
any |
nil
|
extra classes for the palette panel inside the dialog |
id*
|
string |
unique id for the dialog; open it with ⌘K or open_command/1 | |
loop
|
boolean |
false
|
arrow keys wrap around the list |
reset_on_close
|
boolean |
true
|
clear the query (and restore all items) when the dialog closes |
rest
|
global |
||
shortcut
|
string |
"k"
|
the key bound with Cmd (mac) / Ctrl to toggle the dialog. Set to nil to disable the global binding |
:inner_block
slot
|
slot |
| Attribute | Type | Default | Description |
|---|---|---|---|
class
|
any |
nil
|
|
disabled
|
boolean |
false
|
|
href
|
string |
nil
|
plain link target - renders the item as a link |
keywords
|
list |
[]
|
extra search aliases for this item |
navigate
|
string |
nil
|
live_redirect target - renders the item as a link |
patch
|
string |
nil
|
live_patch target - renders the item as a link |
rest
|
global |
phx-click and friends work here - Enter clicks the highlighted item | |
value
|
string |
nil
|
the text the filter matches against. Defaults to the item's visible text |
:inner_block
slot
|
slot |