Zaidan

Command Palette

Search for a command to run...

GitHub43

Command

Fast, composable command menu for SolidJS.

Installation

CLI

Manual

Copy and paste the following code into your project.

import { Command as CommandPrimitive } from "cmdk-solid";
import { Check, SearchIcon } from "lucide-solid";
import { type ComponentProps, mergeProps, splitProps } from "solid-js";
import { cn } from "~/lib/utils";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from "~/components/ui/dialog";
import { InputGroup, InputGroupAddon } from "~/components/ui/input-group";
function Command(props: ComponentProps<"div">) {
return (
<CommandPrimitive
data-slot="command"
class={cn("z-command flex size-full flex-col overflow-hidden", props.class)}
{...props}
/>
);
}
type CommandDialogProps = ComponentProps<typeof Dialog> &
Pick<ComponentProps<"div">, "class"> & {
title?: string;
description?: string;
showCloseButton?: boolean;
};
function CommandDialog(props: CommandDialogProps) {
const mergedProps = mergeProps(
{
title: "Command Palette",
description: "Search for a command to run...",
showCloseButton: false,
},
props,
);
const [local, others] = splitProps(mergedProps as CommandDialogProps, [
"title",
"description",
"showCloseButton",
"children",
"class",
]);
return (
<Dialog {...others}>
<DialogHeader class="sr-only">
<DialogTitle>{local.title}</DialogTitle>
<DialogDescription>{local.description}</DialogDescription>
</DialogHeader>
<DialogContent
class={cn("z-command-dialog overflow-hidden p-0", local.class)}
showCloseButton={local.showCloseButton}
>
{local.children}
</DialogContent>
</Dialog>
);
}
function CommandInput(props: ComponentProps<typeof CommandPrimitive.Input>) {
const [local, others] = splitProps(props, ["class"]);
return (
<div data-slot="command-input-wrapper" class="z-command-input-wrapper">
<InputGroup class="z-command-input-group">
<CommandPrimitive.Input
data-slot="command-input"
class={cn(
"z-command-input outline-hidden disabled:cursor-not-allowed disabled:opacity-50",
local.class,
)}
{...others}
/>
<InputGroupAddon>
<SearchIcon class="z-command-input-icon" />
</InputGroupAddon>
</InputGroup>
</div>
);
}
function CommandList(props: ComponentProps<typeof CommandPrimitive.List>) {
const [local, others] = splitProps(props, ["class"]);
return (
<CommandPrimitive.List
data-slot="command-list"
class={cn("z-command-list overflow-y-auto overflow-x-hidden", local.class)}
{...others}
/>
);
}
function CommandEmpty(props: ComponentProps<typeof CommandPrimitive.Empty>) {
const [local, others] = splitProps(props, ["class"]);
return (
<CommandPrimitive.Empty
data-slot="command-empty"
class={cn("z-command-empty", local.class)}
{...others}
/>
);
}
function CommandGroup(props: ComponentProps<typeof CommandPrimitive.Group>) {
const [local, others] = splitProps(props, ["class"]);
return (
<CommandPrimitive.Group
data-slot="command-group"
class={cn("z-command-group", local.class)}
{...others}
/>
);
}
function CommandSeparator(props: ComponentProps<typeof CommandPrimitive.Separator>) {
const [local, others] = splitProps(props, ["class"]);
return (
<CommandPrimitive.Separator
data-slot="command-separator"
class={cn("z-command-separator", local.class)}
{...others}
/>
);
}
function CommandItem(props: ComponentProps<typeof CommandPrimitive.Item>) {
const [local, others] = splitProps(props, ["class", "children"]);
return (
<CommandPrimitive.Item
data-slot="command-item"
class={cn(
"group/command-item z-command-item data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
local.class,
)}
{...others}
>
{local.children}
<Check class="z-command-item-indicator ml-auto opacity-0 group-has-data-[slot=command-shortcut]/command-item:hidden group-data-[checked=true]/command-item:opacity-100" />
</CommandPrimitive.Item>
);
}
function CommandShortcut(props: ComponentProps<"span">) {
const [local, others] = splitProps(props, ["class"]);
return (
<span data-slot="command-shortcut" class={cn("z-command-shortcut", local.class)} {...others} />
);
}
export {
Command,
CommandDialog,
CommandInput,
CommandList,
CommandEmpty,
CommandGroup,
CommandItem,
CommandShortcut,
CommandSeparator,
};

Props

Command

The root container for the command menu. Provides search context for filtering.

PropTypeDefaultDescription
classstring-Additional CSS classes

CommandDialog

A dialog variant that wraps the command menu in a modal.

PropTypeDefaultDescription
openboolean-Controlled open state
onOpenChange(open: boolean) => void-Handler called when open state changes
titlestring"Command Palette"Accessible title for screen readers
descriptionstring"Search for a command to run..."Accessible description for screen readers
showCloseButtonbooleanfalseShow the close button
classstring-Additional CSS classes

CommandInput

The search input field with integrated search icon.

PropTypeDefaultDescription
placeholderstring-Placeholder text
disabledbooleanfalseWhether the input is disabled
classstring-Additional CSS classes

CommandList

Scrollable container for command items.

PropTypeDefaultDescription
classstring-Additional CSS classes

CommandEmpty

Displayed when no items match the search query.

PropTypeDefaultDescription
classstring-Additional CSS classes

CommandGroup

Groups related command items with an optional heading.

PropTypeDefaultDescription
headingstring-The group heading text
classstring-Additional CSS classes

CommandItem

Individual selectable command item with filtering support.

PropTypeDefaultDescription
valuestring-The value used for filtering (required for search to work)
keywordsstring[]-Additional keywords to match during search
disabledbooleanfalseWhether the item is disabled
onSelect() => void-Handler called when item is selected
classstring-Additional CSS classes

CommandSeparator

Visual separator between command groups.

PropTypeDefaultDescription
classstring-Additional CSS classes

CommandShortcut

Displays keyboard shortcuts aligned to the right of a command item.

PropTypeDefaultDescription
classstring-Additional CSS classes

Filtering

The Command component includes built-in filtering. Each CommandItem must have a value prop that is used for matching against the search query. You can also provide additional keywords for more flexible matching:

<CommandItem value="new-file" keywords={["create", "add"]}>
<Plus />
<span>New File</span>
</CommandItem>

Items that don't match the search query are automatically hidden.

Examples

Here are the source code of all the examples from the preview page:

Basic

import { createSignal } from "solid-js";
import { Button } from "~/components/ui/button";
import {
Command,
CommandDialog,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "~/components/ui/command";
function CommandBasic() {
const [open, setOpen] = createSignal(false);
return (
<Example title="Basic">
<div class="flex flex-col gap-4">
<Button onClick={() => setOpen(true)} variant="outline" class="w-fit">
Open Menu
</Button>
<CommandDialog open={open()} onOpenChange={setOpen}>
<Command>
<CommandInput placeholder="Type a command or search..." />
<CommandList>
<CommandEmpty>No results found.</CommandEmpty>
<CommandGroup heading="Suggestions">
<CommandItem value="calendar">Calendar</CommandItem>
<CommandItem value="search-emoji">Search Emoji</CommandItem>
<CommandItem value="calculator">Calculator</CommandItem>
</CommandGroup>
</CommandList>
</Command>
</CommandDialog>
</div>
</Example>
);
}

With Shortcuts

import { CreditCard, Settings, User } from "lucide-solid";
import { createSignal } from "solid-js";
import { Button } from "~/components/ui/button";
import {
Command,
CommandDialog,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
CommandShortcut,
} from "~/components/ui/command";
function CommandWithShortcuts() {
const [open, setOpen] = createSignal(false);
return (
<Example title="With Shortcuts">
<div class="flex flex-col gap-4">
<Button onClick={() => setOpen(true)} variant="outline" class="w-fit">
Open Menu
</Button>
<CommandDialog open={open()} onOpenChange={setOpen}>
<Command>
<CommandInput placeholder="Type a command or search..." />
<CommandList>
<CommandEmpty>No results found.</CommandEmpty>
<CommandGroup heading="Settings">
<CommandItem value="profile">
<User />
<span>Profile</span>
<CommandShortcut>⌘P</CommandShortcut>
</CommandItem>
<CommandItem value="billing">
<CreditCard />
<span>Billing</span>
<CommandShortcut>⌘B</CommandShortcut>
</CommandItem>
<CommandItem value="settings">
<Settings />
<span>Settings</span>
<CommandShortcut>⌘S</CommandShortcut>
</CommandItem>
</CommandGroup>
</CommandList>
</Command>
</CommandDialog>
</div>
</Example>
);
}

With Groups

import {
Calculator,
Calendar,
CreditCard,
Settings,
Smile,
User,
} from "lucide-solid";
import { createSignal } from "solid-js";
import { Button } from "~/components/ui/button";
import {
Command,
CommandDialog,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
CommandSeparator,
CommandShortcut,
} from "~/components/ui/command";
function CommandWithGroups() {
const [open, setOpen] = createSignal(false);
return (
<Example title="With Groups">
<div class="flex flex-col gap-4">
<Button onClick={() => setOpen(true)} variant="outline" class="w-fit">
Open Menu
</Button>
<CommandDialog open={open()} onOpenChange={setOpen}>
<Command>
<CommandInput placeholder="Type a command or search..." />
<CommandList>
<CommandEmpty>No results found.</CommandEmpty>
<CommandGroup heading="Suggestions">
<CommandItem value="calendar">
<Calendar />
<span>Calendar</span>
</CommandItem>
<CommandItem value="search-emoji">
<Smile />
<span>Search Emoji</span>
</CommandItem>
<CommandItem value="calculator">
<Calculator />
<span>Calculator</span>
</CommandItem>
</CommandGroup>
<CommandSeparator />
<CommandGroup heading="Settings">
<CommandItem value="profile">
<User />
<span>Profile</span>
<CommandShortcut>⌘P</CommandShortcut>
</CommandItem>
<CommandItem value="billing">
<CreditCard />
<span>Billing</span>
<CommandShortcut>⌘B</CommandShortcut>
</CommandItem>
<CommandItem value="settings">
<Settings />
<span>Settings</span>
<CommandShortcut>⌘S</CommandShortcut>
</CommandItem>
</CommandGroup>
</CommandList>
</Command>
</CommandDialog>
</div>
</Example>
);
}

Many Groups & Items

import {
Bell,
Calculator,
Calendar,
ClipboardPaste,
Code,
Copy,
CreditCard,
FileText,
Folder,
FolderPlus,
HelpCircle,
Home,
Image,
Inbox,
LayoutGrid,
List,
Plus,
Scissors,
Settings,
Trash,
User,
ZoomIn,
ZoomOut,
} from "lucide-solid";
import { createSignal } from "solid-js";
import { Button } from "~/components/ui/button";
import {
Command,
CommandDialog,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
CommandSeparator,
CommandShortcut,
} from "~/components/ui/command";
function CommandManyItems() {
const [open, setOpen] = createSignal(false);
return (
<Example title="Many Groups & Items">
<div class="flex flex-col gap-4">
<Button onClick={() => setOpen(true)} variant="outline" class="w-fit">
Open Menu
</Button>
<CommandDialog open={open()} onOpenChange={setOpen}>
<Command>
<CommandInput placeholder="Type a command or search..." />
<CommandList>
<CommandEmpty>No results found.</CommandEmpty>
<CommandGroup heading="Navigation">
<CommandItem value="home">
<Home />
<span>Home</span>
<CommandShortcut>⌘H</CommandShortcut>
</CommandItem>
<CommandItem value="inbox">
<Inbox />
<span>Inbox</span>
<CommandShortcut>⌘I</CommandShortcut>
</CommandItem>
<CommandItem value="documents">
<FileText />
<span>Documents</span>
<CommandShortcut>⌘D</CommandShortcut>
</CommandItem>
<CommandItem value="folders">
<Folder />
<span>Folders</span>
<CommandShortcut>⌘F</CommandShortcut>
</CommandItem>
</CommandGroup>
<CommandSeparator />
<CommandGroup heading="Actions">
<CommandItem value="new-file">
<Plus />
<span>New File</span>
<CommandShortcut>⌘N</CommandShortcut>
</CommandItem>
<CommandItem value="new-folder">
<FolderPlus />
<span>New Folder</span>
<CommandShortcut>⇧⌘N</CommandShortcut>
</CommandItem>
<CommandItem value="copy">
<Copy />
<span>Copy</span>
<CommandShortcut>⌘C</CommandShortcut>
</CommandItem>
<CommandItem value="cut">
<Scissors />
<span>Cut</span>
<CommandShortcut>⌘X</CommandShortcut>
</CommandItem>
<CommandItem value="paste">
<ClipboardPaste />
<span>Paste</span>
<CommandShortcut>⌘V</CommandShortcut>
</CommandItem>
<CommandItem value="delete">
<Trash />
<span>Delete</span>
<CommandShortcut>⌘⌫</CommandShortcut>
</CommandItem>
</CommandGroup>
<CommandSeparator />
<CommandGroup heading="View">
<CommandItem value="grid-view">
<LayoutGrid />
<span>Grid View</span>
</CommandItem>
<CommandItem value="list-view">
<List />
<span>List View</span>
</CommandItem>
<CommandItem value="zoom-in">
<ZoomIn />
<span>Zoom In</span>
<CommandShortcut>⌘+</CommandShortcut>
</CommandItem>
<CommandItem value="zoom-out">
<ZoomOut />
<span>Zoom Out</span>
<CommandShortcut>⌘-</CommandShortcut>
</CommandItem>
</CommandGroup>
<CommandSeparator />
<CommandGroup heading="Account">
<CommandItem value="profile">
<User />
<span>Profile</span>
<CommandShortcut>⌘P</CommandShortcut>
</CommandItem>
<CommandItem value="billing">
<CreditCard />
<span>Billing</span>
<CommandShortcut>⌘B</CommandShortcut>
</CommandItem>
<CommandItem value="settings">
<Settings />
<span>Settings</span>
<CommandShortcut>⌘S</CommandShortcut>
</CommandItem>
<CommandItem value="notifications">
<Bell />
<span>Notifications</span>
</CommandItem>
<CommandItem value="help">
<HelpCircle />
<span>Help & Support</span>
</CommandItem>
</CommandGroup>
<CommandSeparator />
<CommandGroup heading="Tools">
<CommandItem value="calculator">
<Calculator />
<span>Calculator</span>
</CommandItem>
<CommandItem value="calendar">
<Calendar />
<span>Calendar</span>
</CommandItem>
<CommandItem value="image-editor">
<Image />
<span>Image Editor</span>
</CommandItem>
<CommandItem value="code-editor">
<Code />
<span>Code Editor</span>
</CommandItem>
</CommandGroup>
</CommandList>
</Command>
</CommandDialog>
</div>
</Example>
);
}