This component features a Dialog-based command menu with extensive keyboard shortcuts and multiple action categories.
Installation
Install the component using the CLI:npx shadcn@latest add command-menu-02
Dependencies
This component requires the following dependencies:- button
- command
- dialog
- kbd
- @tabler/icons-react
Usage
import { CommandMenu02 } from "@/components/command-menu-02";
export default function Page() {
return <CommandMenu02 />;
}
Features
- Keyboard Shortcuts: Displays shortcuts using Kbd and KbdGroup components
- Multiple Categories: Documents, Signing, Templates, General, Navigation, Quick Actions, and Help
- Custom Dialog: Uses Dialog component with custom styling
- Controlled Input: Tracks input value state
- ESC in Header: Shows ESC shortcut in the header for quick access
- Extensive Actions: Over 30 different commands organized by category
Component Structure
The component includes eight main groups:Account Actions
Account Settings, Switch Workspace, and Log Out with their respective keyboard shortcuts.Documents
Search, create, and upload documents with keyboard shortcuts like⌘F, ⌘N, and ⌘U.
Signing
Request signatures, sign documents, and bulk send for signatures.Templates
Search and create templates.General
Theme changes and URL copying with shortcuts.Navigation
Quick navigation to Inbox, Action Required, Waiting for Others, Completed, Drafts, Templates, Archive, Trash, and Settings.Quick Actions
Copy signing links and download documents.Help
Search help center, send feedback, and contact support.Code
"use client";
import {
IconArrowRight,
IconAt,
IconCopy,
IconDeviceDesktop,
IconDownload,
IconFile,
IconFileSearch,
IconKeyboard,
IconLink,
IconLogout,
IconMessage,
IconPencil,
IconPlus,
IconSend,
IconSettings,
IconTemplate,
IconUser,
IconUsers,
} from "@tabler/icons-react";
import { useEffect, useState } from "react";
import { Button } from "@/components/ui/button";
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "@/components/ui/command";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Kbd, KbdGroup } from "@/components/ui/kbd";
export function CommandMenu02() {
const [open, setOpen] = useState(true);
const [inputValue, setInputValue] = useState("");
useEffect(() => {
const down = (e: KeyboardEvent) => {
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
e.preventDefault();
setOpen((prev) => !prev);
}
};
document.addEventListener("keydown", down);
return () => document.removeEventListener("keydown", down);
}, []);
return (
<>
<Button onClick={() => setOpen(true)} variant="outline">
Open Command Menu
</Button>
<Dialog onOpenChange={setOpen} open={open}>
<DialogHeader className="sr-only">
<DialogTitle>Command Menu</DialogTitle>
<DialogDescription>
Use the command menu to navigate through the app.
</DialogDescription>
</DialogHeader>
<DialogContent
className="gap-0 overflow-hidden rounded-xl border-border/50 p-0 shadow-lg sm:max-w-lg"
showCloseButton={false}
>
<Command className="flex h-full w-full flex-col overflow-hidden bg-popover **:data-[slot=command-input-wrapper]:h-auto **:data-[slot=command-input-wrapper]:grow **:data-[slot=command-input-wrapper]:border-0 **:data-[slot=command-input-wrapper]:px-0">
<div className="flex h-12 items-center gap-2 border-border/50 border-b px-4">
<CommandInput
className="h-10 text-[15px]"
onValueChange={setInputValue}
placeholder="What do you need?"
value={inputValue}
/>
<button
className="flex shrink-0 items-center"
onClick={() => setOpen(false)}
type="button"
>
<Kbd>Esc</Kbd>
</button>
</div>
<CommandList className="max-h-[400px] py-2">
<CommandEmpty>No results found.</CommandEmpty>
<CommandGroup>
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconSettings aria-hidden />
Account Settings...
<KbdGroup className="ml-auto">
<Kbd>⌘</Kbd>
<Kbd>,</Kbd>
</KbdGroup>
</CommandItem>
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconUser aria-hidden />
Switch Workspace...
</CommandItem>
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconLogout aria-hidden />
Log Out
<KbdGroup className="ml-auto">
<Kbd>⌘</Kbd>
<Kbd>Q</Kbd>
</KbdGroup>
</CommandItem>
</CommandGroup>
<CommandGroup heading="Documents">
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconFile aria-hidden />
Search Documents...
<KbdGroup className="ml-auto">
<Kbd>⌘</Kbd>
<Kbd>F</Kbd>
</KbdGroup>
</CommandItem>
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconPlus aria-hidden />
Create New Document...
<KbdGroup className="ml-auto">
<Kbd>⌘</Kbd>
<Kbd>N</Kbd>
</KbdGroup>
</CommandItem>
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconFile aria-hidden />
Upload Document...
<KbdGroup className="ml-auto">
<Kbd>⌘</Kbd>
<Kbd>U</Kbd>
</KbdGroup>
</CommandItem>
</CommandGroup>
<CommandGroup heading="Signing">
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconSend aria-hidden />
Request Signature...
</CommandItem>
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconPencil aria-hidden />
Sign a Document...
</CommandItem>
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconUsers aria-hidden />
Bulk Send for Signature...
</CommandItem>
</CommandGroup>
<CommandGroup heading="Templates">
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconTemplate aria-hidden />
Search Templates...
</CommandItem>
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconPlus aria-hidden />
Create New Template...
</CommandItem>
</CommandGroup>
<CommandGroup heading="General">
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconDeviceDesktop aria-hidden />
Change Theme...
<KbdGroup className="ml-auto">
<Kbd>⌘</Kbd>
<Kbd>T</Kbd>
</KbdGroup>
</CommandItem>
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconCopy aria-hidden />
Copy Current URL
<KbdGroup className="ml-auto">
<Kbd>⌘</Kbd>
<Kbd>⇧</Kbd>
<Kbd>C</Kbd>
</KbdGroup>
</CommandItem>
</CommandGroup>
<CommandGroup heading="Navigation">
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconArrowRight aria-hidden />
<span>
Go to <strong className="font-semibold">Inbox</strong>
</span>
</CommandItem>
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconArrowRight aria-hidden />
<span>
Go to
<strong className="font-semibold">Action Required</strong>
</span>
</CommandItem>
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconArrowRight aria-hidden />
<span>
Go to
<strong className="font-semibold">
Waiting for Others
</strong>
</span>
</CommandItem>
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconArrowRight aria-hidden />
<span>
Go to
<strong className="font-semibold">Completed</strong>
</span>
</CommandItem>
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconArrowRight aria-hidden />
<span>
Go to <strong className="font-semibold">Drafts</strong>
</span>
</CommandItem>
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconArrowRight aria-hidden />
<span>
Go to
<strong className="font-semibold">Templates</strong>
</span>
</CommandItem>
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconArrowRight aria-hidden />
<span>
Go to
<strong className="font-semibold">Archive</strong>
</span>
</CommandItem>
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconArrowRight aria-hidden />
<span>
Go to <strong className="font-semibold">Trash</strong>
</span>
</CommandItem>
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconArrowRight aria-hidden />
<span>
Go to
<strong className="font-semibold">Settings</strong>
</span>
</CommandItem>
</CommandGroup>
<CommandGroup heading="Quick Actions">
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconLink aria-hidden />
Copy Signing Link
</CommandItem>
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconDownload aria-hidden />
Download Document
</CommandItem>
</CommandGroup>
<CommandGroup heading="Help">
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconFileSearch aria-hidden />
Search Help Center...
</CommandItem>
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconMessage aria-hidden />
Send Feedback...
</CommandItem>
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconAt aria-hidden />
Contact Support
</CommandItem>
</CommandGroup>
<CommandGroup heading="Keyboard Shortcuts">
<CommandItem
className="mx-2 rounded-lg py-2.5"
onSelect={() => setOpen(false)}
>
<IconKeyboard aria-hidden />
View Keyboard Shortcuts
<KbdGroup className="ml-auto">
<Kbd>⌘</Kbd>
<Kbd>/</Kbd>
</KbdGroup>
</CommandItem>
</CommandGroup>
</CommandList>
</Command>
</DialogContent>
</Dialog>
</>
);
}