Command

Fast, composable, unstyled command menu for React.

About

The <Command /> component uses the cmdk component by pacocoursey.

Installation

Install the following dependencies:

npm install cmdk

Copy and paste the following code into your project.

'use client';
 
import { type DialogProps } from '@radix-ui/react-dialog';
import clsx from 'clsx';
import { Command as CommandPrimitive } from 'cmdk';
import { Search } from 'lucide-react';
import { ComponentPropsWithoutRef, ElementRef, HTMLAttributes, forwardRef } from 'react';
import { Dialog, DialogContent } from '../dialog';
import styles from './styles.module.scss';
 
const Command = forwardRef<ElementRef<typeof CommandPrimitive>, ComponentPropsWithoutRef<typeof CommandPrimitive>>(
    ({ className, ...props }, ref) => (
        <CommandPrimitive ref={ref} className={clsx(styles.command, className)} {...props} />
    )
);
Command.displayName = CommandPrimitive.displayName;
 
type CommandDialogProps = DialogProps;
 
const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
    return (
        <Dialog {...props}>
            <DialogContent className={styles.command__dialog}>
                <Command className={styles.command__dialog__command}>{children}</Command>
            </DialogContent>
        </Dialog>
    );
};
 
const CommandInput = forwardRef<
    ElementRef<typeof CommandPrimitive.Input>,
    ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
>(({ className, ...props }, ref) => (
    <div className={styles.command__input__container} cmdk-input-wrapper=''>
        <Search className={styles.command__input__search} />
        <CommandPrimitive.Input ref={ref} className={clsx(styles.command__input, className)} {...props} />
    </div>
));
 
CommandInput.displayName = CommandPrimitive.Input.displayName;
 
const CommandList = forwardRef<
    ElementRef<typeof CommandPrimitive.List>,
    ComponentPropsWithoutRef<typeof CommandPrimitive.List>
>(({ className, ...props }, ref) => (
    <CommandPrimitive.List ref={ref} className={clsx(styles.command__list, className)} {...props} />
));
 
CommandList.displayName = CommandPrimitive.List.displayName;
 
const CommandEmpty = forwardRef<
    ElementRef<typeof CommandPrimitive.Empty>,
    ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
>((props, ref) => <CommandPrimitive.Empty ref={ref} className={styles.command__empty} {...props} />);
 
CommandEmpty.displayName = CommandPrimitive.Empty.displayName;
 
const CommandGroup = forwardRef<
    ElementRef<typeof CommandPrimitive.Group>,
    ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
>(({ className, ...props }, ref) => (
    <CommandPrimitive.Group ref={ref} className={clsx(styles.command_group, className)} {...props} />
));
 
CommandGroup.displayName = CommandPrimitive.Group.displayName;
 
const CommandSeparator = forwardRef<
    ElementRef<typeof CommandPrimitive.Separator>,
    ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
>(({ className, ...props }, ref) => (
    <CommandPrimitive.Separator ref={ref} className={clsx(styles.command__separator, className)} {...props} />
));
CommandSeparator.displayName = CommandPrimitive.Separator.displayName;
 
const CommandItem = forwardRef<
    ElementRef<typeof CommandPrimitive.Item>,
    ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
>(({ className, ...props }, ref) => (
    <CommandPrimitive.Item ref={ref} className={clsx(styles.command__item, className)} {...props} />
));
 
CommandItem.displayName = CommandPrimitive.Item.displayName;
 
const CommandShortcut = ({ className, ...props }: HTMLAttributes<HTMLSpanElement>) => {
    return <span className={clsx(styles.command__shortcut, className)} {...props} />;
};
CommandShortcut.displayName = 'CommandShortcut';
 
export {
    Command,
    CommandDialog,
    CommandEmpty,
    CommandGroup,
    CommandInput,
    CommandItem,
    CommandList,
    CommandSeparator,
    CommandShortcut,
};

Update the import paths to match your project setup.

Usage

import {
    Command,
    CommandDialog,
    CommandEmpty,
    CommandGroup,
    CommandInput,
    CommandItem,
    CommandList,
    CommandSeparator,
    CommandShortcut,
} from '@/components/ui/command';
<Command>
    <CommandInput placeholder='Type a command or search...' />
    <CommandList>
        <CommandEmpty>No results found.</CommandEmpty>
        <CommandGroup heading='Suggestions'>
            <CommandItem>Calendar</CommandItem>
            <CommandItem>Search Emoji</CommandItem>
            <CommandItem>Calculator</CommandItem>
        </CommandGroup>
        <CommandSeparator />
        <CommandGroup heading='Settings'>
            <CommandItem>Profile</CommandItem>
            <CommandItem>Billing</CommandItem>
            <CommandItem>Settings</CommandItem>
        </CommandGroup>
    </CommandList>
</Command>

Examples

Dialog

Press J

To show the command menu in a dialog, use the <CommandDialog /> component.

export function CommandMenu() {
    const [open, setOpen] = React.useState(false);
 
    React.useEffect(() => {
        const down = (e: KeyboardEvent) => {
            if (e.key === 'k' && (e.metaKey || e.ctrlKey)) {
                e.preventDefault();
                setOpen((open) => !open);
            }
        };
        document.addEventListener('keydown', down);
        return () => document.removeEventListener('keydown', down);
    }, []);
 
    return (
        <CommandDialog open={open} onOpenChange={setOpen}>
            <CommandInput placeholder='Type a command or search...' />
            <CommandList>
                <CommandEmpty>No results found.</CommandEmpty>
                <CommandGroup heading='Suggestions'>
                    <CommandItem>Calendar</CommandItem>
                    <CommandItem>Search Emoji</CommandItem>
                    <CommandItem>Calculator</CommandItem>
                </CommandGroup>
            </CommandList>
        </CommandDialog>
    );
}

Combobox

You can use the <Command /> component as a combobox. See the Combobox page for more information.