Command
A command menu component for command interfaces. Built with cmdk.
Suggestions
Calendar
Search Emoji
Email
Documents
Settings
Profile
Billing
Terminal
"use client";
import { Calendar, CreditCard, FileText, Mail, Smile, Terminal, User } from "lucide-react";
import { useCallback, useState } from "react";
import { EnterArrowIcon } from "@/components/ui/arrow-icon/arrow-icon";
import {
Command,
CommandCollection,
CommandEmpty,
CommandFooter,
CommandGroup,
CommandGroupLabel,
CommandInput,
CommandItem,
CommandList,
CommandSeparator,
} from "@/components/ui/command/command";
import { Kbd } from "@/components/ui/kbd/kbd";
import styles from "./command-demo.module.css";
type CommandItemData = {
id: string;
label: string;
icon: React.ReactNode;
group: string;
};
const suggestions: CommandItemData[] = [
{ id: "calendar", label: "Calendar", icon: <Calendar size={16} />, group: "Suggestions" },
{ id: "emoji", label: "Search Emoji", icon: <Smile size={16} />, group: "Suggestions" },
{ id: "email", label: "Email", icon: <Mail size={16} />, group: "Suggestions" },
{ id: "documents", label: "Documents", icon: <FileText size={16} />, group: "Suggestions" },
];
const settings: CommandItemData[] = [
{ id: "profile", label: "Profile", icon: <User size={16} />, group: "Settings" },
{ id: "billing", label: "Billing", icon: <CreditCard size={16} />, group: "Settings" },
{ id: "terminal", label: "Terminal", icon: <Terminal size={16} />, group: "Settings" },
];
const allItems = [...suggestions, ...settings];
export default function CommandDemo() {
const [inputValue, setInputValue] = useState("");
const handleValueChange = useCallback((value: string) => {
setInputValue(value);
}, []);
const itemToStringValue = useCallback(
(item: unknown) => (item && typeof item === "object" && "label" in item ? (item as CommandItemData).label : ""),
[]
);
const filteredSuggestions = suggestions.filter((item) =>
item.label.toLowerCase().includes(inputValue.toLowerCase())
);
const filteredSettings = settings.filter((item) =>
item.label.toLowerCase().includes(inputValue.toLowerCase())
);
return (
<Command
className={styles.command}
items={allItems}
itemToStringValue={itemToStringValue}
onValueChange={handleValueChange}
>
<CommandInput className={styles.commandInput} placeholder="Type a command or search..." />
<CommandList>
{filteredSuggestions.length === 0 && filteredSettings.length === 0 && (
<CommandEmpty>No results found.</CommandEmpty>
)}
{filteredSuggestions.length > 0 && (
<CommandGroup items={filteredSuggestions}>
<CommandGroupLabel>Suggestions</CommandGroupLabel>
<CommandCollection>
{(item: CommandItemData) => (
<CommandItem key={item.id} value={item}>
{item.icon}
{item.label}
</CommandItem>
)}
</CommandCollection>
</CommandGroup>
)}
{filteredSuggestions.length > 0 && filteredSettings.length > 0 && <CommandSeparator />}
{filteredSettings.length > 0 && (
<CommandGroup items={filteredSettings}>
<CommandGroupLabel>Settings</CommandGroupLabel>
<CommandCollection>
{(item: CommandItemData) => (
<CommandItem key={item.id} value={item}>
{item.icon}
{item.label}
</CommandItem>
)}
</CommandCollection>
</CommandGroup>
)}
</CommandList>
<CommandFooter>
<div className={styles.commandFooterItem}>
<Kbd className={styles.commandFooterKbd} size="md">
<EnterArrowIcon />
</Kbd>
<span className={styles.commandFooterText}>to select</span>
</div>
</CommandFooter>
</Command>
);
}
npx shadcn@latest add @roiui/commandnpx shadcn@latest add @roiui/command-tailwindanatomy
<Command>
<CommandInput />
<CommandList>
<CommandEmpty />
<CommandGroup>
<CommandItem />
<CommandSeparator />
</CommandGroup>
<CommandLoading />
</CommandList>
</Command>