Search for a command to run...
Fast, composable command menu for SolidJS.
npx shadcn@latest add @zaidan/commandpnpx shadcn add @zaidan/commandyarn dlx shadcn@latest add @zaidan/commandbunx shadcn@latest add @zaidan/commandCopy and paste the following code into your project.
1import { Command as CommandPrimitive } from "cmdk-solid";2import { Check, SearchIcon } from "lucide-solid";3import { type ComponentProps, mergeProps, splitProps } from "solid-js";4import { cn } from "~/lib/utils";5import {6 Dialog,7 DialogContent,8 DialogDescription,9 DialogHeader,10 DialogTitle,11} from "~/components/ui/dialog";12import { InputGroup, InputGroupAddon } from "~/components/ui/input-group";13
14function Command(props: ComponentProps<"div">) {15 return (16 <CommandPrimitive17 data-slot="command"18 class={cn("z-command flex size-full flex-col overflow-hidden", props.class)}19 {...props}20 />21 );22}23
24type CommandDialogProps = ComponentProps<typeof Dialog> &25 Pick<ComponentProps<"div">, "class"> & {26 title?: string;27 description?: string;28 showCloseButton?: boolean;29 };30
31function CommandDialog(props: CommandDialogProps) {32 const mergedProps = mergeProps(33 {34 title: "Command Palette",35 description: "Search for a command to run...",36 showCloseButton: false,37 },38 props,39 );40
41 const [local, others] = splitProps(mergedProps as CommandDialogProps, [42 "title",43 "description",44 "showCloseButton",45 "children",46 "class",47 ]);48
49 return (50 <Dialog {...others}>51 <DialogHeader class="sr-only">52 <DialogTitle>{local.title}</DialogTitle>53 <DialogDescription>{local.description}</DialogDescription>54 </DialogHeader>55 <DialogContent56 class={cn("z-command-dialog overflow-hidden p-0", local.class)}57 showCloseButton={local.showCloseButton}58 >59 {local.children}60 </DialogContent>61 </Dialog>62 );63}64
65function CommandInput(props: ComponentProps<typeof CommandPrimitive.Input>) {66 const [local, others] = splitProps(props, ["class"]);67 return (68 <div data-slot="command-input-wrapper" class="z-command-input-wrapper">69 <InputGroup class="z-command-input-group">70 <CommandPrimitive.Input71 data-slot="command-input"72 class={cn(73 "z-command-input outline-hidden disabled:cursor-not-allowed disabled:opacity-50",74 local.class,75 )}76 {...others}77 />78 <InputGroupAddon>79 <SearchIcon class="z-command-input-icon" />80 </InputGroupAddon>81 </InputGroup>82 </div>83 );84}85
86function CommandList(props: ComponentProps<typeof CommandPrimitive.List>) {87 const [local, others] = splitProps(props, ["class"]);88 return (89 <CommandPrimitive.List90 data-slot="command-list"91 class={cn("z-command-list overflow-y-auto overflow-x-hidden", local.class)}92 {...others}93 />94 );95}96
97function CommandEmpty(props: ComponentProps<typeof CommandPrimitive.Empty>) {98 const [local, others] = splitProps(props, ["class"]);99 return (100 <CommandPrimitive.Empty101 data-slot="command-empty"102 class={cn("z-command-empty", local.class)}103 {...others}104 />105 );106}107
108function CommandGroup(props: ComponentProps<typeof CommandPrimitive.Group>) {109 const [local, others] = splitProps(props, ["class"]);110 return (111 <CommandPrimitive.Group112 data-slot="command-group"113 class={cn("z-command-group", local.class)}114 {...others}115 />116 );117}118
119function CommandSeparator(props: ComponentProps<typeof CommandPrimitive.Separator>) {120 const [local, others] = splitProps(props, ["class"]);121 return (122 <CommandPrimitive.Separator123 data-slot="command-separator"124 class={cn("z-command-separator", local.class)}125 {...others}126 />127 );128}129
130function CommandItem(props: ComponentProps<typeof CommandPrimitive.Item>) {131 const [local, others] = splitProps(props, ["class", "children"]);132 return (133 <CommandPrimitive.Item134 data-slot="command-item"135 class={cn(136 "group/command-item z-command-item data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",137 local.class,138 )}139 {...others}140 >141 {local.children}142 <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" />143 </CommandPrimitive.Item>144 );145}146
147function CommandShortcut(props: ComponentProps<"span">) {148 const [local, others] = splitProps(props, ["class"]);149 return (150 <span data-slot="command-shortcut" class={cn("z-command-shortcut", local.class)} {...others} />151 );152}153
154export {155 Command,156 CommandDialog,157 CommandInput,158 CommandList,159 CommandEmpty,160 CommandGroup,161 CommandItem,162 CommandShortcut,163 CommandSeparator,164};The root container for the command menu. Provides search context for filtering.
| Prop | Type | Default | Description |
|---|---|---|---|
class | string | - | Additional CSS classes |
A dialog variant that wraps the command menu in a modal.
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | - | Controlled open state |
onOpenChange | (open: boolean) => void | - | Handler called when open state changes |
title | string | "Command Palette" | Accessible title for screen readers |
description | string | "Search for a command to run..." | Accessible description for screen readers |
showCloseButton | boolean | false | Show the close button |
class | string | - | Additional CSS classes |
The search input field with integrated search icon.
| Prop | Type | Default | Description |
|---|---|---|---|
placeholder | string | - | Placeholder text |
disabled | boolean | false | Whether the input is disabled |
class | string | - | Additional CSS classes |
Scrollable container for command items.
| Prop | Type | Default | Description |
|---|---|---|---|
class | string | - | Additional CSS classes |
Displayed when no items match the search query.
| Prop | Type | Default | Description |
|---|---|---|---|
class | string | - | Additional CSS classes |
Groups related command items with an optional heading.
| Prop | Type | Default | Description |
|---|---|---|---|
heading | string | - | The group heading text |
class | string | - | Additional CSS classes |
Individual selectable command item with filtering support.
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | - | The value used for filtering (required for search to work) |
keywords | string[] | - | Additional keywords to match during search |
disabled | boolean | false | Whether the item is disabled |
onSelect | () => void | - | Handler called when item is selected |
class | string | - | Additional CSS classes |
Visual separator between command groups.
| Prop | Type | Default | Description |
|---|---|---|---|
class | string | - | Additional CSS classes |
Displays keyboard shortcuts aligned to the right of a command item.
| Prop | Type | Default | Description |
|---|---|---|---|
class | string | - | Additional CSS classes |
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.
Here are the source code of all the examples from the preview page:
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> );}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> );}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> );}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> );}