Command
A command palette on cmdk: a search input over a filtered list of commands, inline or in a dialog.
Web only — React, from @krizaka/ui/command. Beta: its API may still change in a minor version.
When to use
- To reach any page or action of an app from the keyboard (⌘K):
CommandDialog. - For a searchable list of choices inside a panel:
Command.Rootinline. - When results come from the server:
shouldFilter={false}andCommand.Loading.
When not to use
- For a short list of actions on one item.Use instead: Dropdown menu
- For a choice among a few options in a form: use a select or radios.Use instead: Radio group
- As the only way to navigate: keep the visible navigation.
Installation
Install
npm install @krizaka/ui@beta @krizaka/tailwind@beta @krizaka/tokens@beta tailwindcssStyles
@import "tailwindcss";
@import "@krizaka/tailwind";
@import "@krizaka/ui/tailwind.css";Import
import { Command, CommandDialog } from "@krizaka/ui/command";Examples
Inline
In a card: the input, groups, shortcuts, a disabled item.
import { Command } from "@krizaka/ui/command";
export default function CommandInline() {
return (
<Command.Root label="Commands" className="w-[28rem] max-w-full rounded-xl border border-border-default shadow-lg">
<Command.Input placeholder="Type a command or search" />
<Command.List label="Suggestions">
<Command.Empty emptyLabel="Nothing matches." />
<Command.Group heading="Pages">
<Command.Item>
Home
<Command.Shortcut>G H</Command.Shortcut>
</Command.Item>
<Command.Item>
Wallet
<Command.Shortcut>G W</Command.Shortcut>
</Command.Item>
<Command.Item disabled>Studio</Command.Item>
</Command.Group>
<Command.Separator />
<Command.Group heading="Actions">
<Command.Item keywords={["video", "new"]}>Upload a video</Command.Item>
<Command.Item>Switch the theme</Command.Item>
</Command.Group>
</Command.List>
</Command.Root>
);
}In a dialog
CommandDialog: the palette of an app, opened from a button or a shortcut.
"use client";
import { Button } from "@krizaka/ui/button";
import { Command, CommandDialog } from "@krizaka/ui/command";
import { Kbd } from "@krizaka/ui/kbd";
import { useState } from "react";
// The palette of an app, in the platform's Dialog: open it from a button or your own ⌘K shortcut.
export default function CommandDialogExample({ defaultOpen = false }: { defaultOpen?: boolean }) {
const [open, setOpen] = useState(defaultOpen);
return (
<>
<Button variant="outline" onClick={() => setOpen(true)}>
Search <Kbd size="sm">⌘K</Kbd>
</Button>
<CommandDialog
open={open}
onOpenChange={setOpen}
label="Search"
footer={<p className="border-t border-border-subtle bg-surface-2 px-4 py-2.5 text-xs text-fg-secondary">↑↓ to move, ↵ to open</p>}
>
<Command.Input placeholder="Search creators, videos, tags" />
<Command.List label="Results">
<Command.Empty emptyLabel="Nothing matches." />
<Command.Group heading="Pages">
<Command.Item onSelect={() => setOpen(false)}>Home</Command.Item>
<Command.Item onSelect={() => setOpen(false)}>Wallet</Command.Item>
</Command.Group>
<Command.Group heading="Actions">
<Command.Item keywords={["video", "new"]}>Upload a video</Command.Item>
</Command.Group>
</Command.List>
</CommandDialog>
</>
);
}Props
CommandRoot
The palette: value / onValueChange (the active item), shouldFilter, filter, loop.
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | — | Accessible label for this command menu. Not shown visibly. The accessible name of the palette — passed translated ("Search", "Commands"). |
CommandInput
The search field (value / onValueChange for the query), with a magnifier.
| Prop | Type | Default | Description |
|---|---|---|---|
placeholderrequired | string | — | What to type — passed translated. The input is named by the palette's label. |
trailing | ReactNode | — | After the input, inside the bar: a spinner, a clear button. |
CommandList
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | — | Accessible label for this List of suggestions. Not shown visibly. The accessible name of the list of results — passed translated ("Suggestions", "Results"). |
CommandEmpty
Shown by cmdk only when no item matches.
| Prop | Type | Default | Description |
|---|---|---|---|
emptyLabelrequired | ReactNode | — | Shown when nothing matches — passed translated. |
CommandDialog
The palette in a dialog (Radix: focus trap, Escape, focus return). The dialog is named by label; it has no close
button — Escape and a click outside close it — and the input takes the focus when it opens.
| Prop | Type | Default | Description |
|---|---|---|---|
contentProps | Omit<DialogContentProps & RefAttributes<HTMLDivElement> & DialogVariants & { closeLabel?: string; hideClose: true; } & { ...; }, "children" | ... 1 more ... | "hideClose"> | — | Passed to Dialog.Content: size, container, className of the dialog. |
defaultOpen | boolean | — | Open at first, uncontrolled. |
footer | ReactNode | — | Under the palette, inside the dialog: shortcuts, a "see all results" link. |
label | string | — | Accessible label for this command menu. Not shown visibly. The accessible name of the palette — passed translated ("Search", "Commands"). |
onOpenChange | ((open: boolean) => void) | — | Called when it opens or closes (Escape, a click outside, a shortcut of the product). |
open | boolean | — | Open or closed (controlled), with onOpenChange. |
Accessibility
- A combobox and a listbox: the input owns
aria-activedescendant, the results are options. labelnames the palette,Command.List labelthe results.CommandDialogtraps the focus in the platform's Dialog and puts it in the input when it opens.
Keyboard
| Keys | Action |
|---|---|
| Arrow keys | Move through the results. |
| Enter | Runs the highlighted command. |
| Esc | Closes the CommandDialog and returns the focus. |
Best practices
- Group the commands (
Command.Group heading) and show their shortcuts withCommand.Shortcut. - Add
keywordsso a command is found by the words people type, not only by its label. - Always say what an empty search means with
Command.Empty emptyLabel.
Related components
Generated from the code of @krizaka/ui 2.0.0-beta.6: its meta.ts, its examples and its types.Edit this documentation on GitHub