web-ux-command-palette
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCommand Palette Pattern
命令面板模式
Overview
概述
Build performant, keyboard-first command palettes using cmdk (the industry standard) with shadcn/ui components.
Why cmdk + shadcn:
- De facto standard (Vercel, Linear, Raycast-style UIs)
- Built-in fuzzy search
- Accessible (Radix Dialog primitives)
- Keyboard-first design
使用cmdk(行业标准工具)搭配shadcn/ui组件,构建高性能、优先支持键盘操作的命令面板。
选择cmdk + shadcn的原因:
- 事实上的标准(适配Vercel、Linear、Raycast风格的UI)
- 内置模糊搜索功能
- 无障碍支持(基于Radix Dialog原语)
- 优先键盘操作的设计
Core Components
核心组件
| Component | Purpose |
|---|---|
| Modal wrapper (Dialog + Command) |
| Search input with icon |
| Scrollable results container |
| "No results" state |
| Categorized sections with headings |
| Individual selectable items |
| Visual divider between groups |
| Keyboard shortcut hint display |
| 组件 | 用途 |
|---|---|
| 模态框包装器(Dialog + Command) |
| 带图标的搜索输入框 |
| 可滚动的结果容器 |
| “无结果”状态展示 |
| 带标题的分类区域 |
| 单个可选项目 |
| 分组间的视觉分隔线 |
| 键盘快捷键提示展示 |
Basic Structure
基础结构
tsx
<CommandDialog open={open} onOpenChange={setOpen}>
<CommandInput placeholder="Type a command..." />
<CommandList>
<CommandEmpty>No results found.</CommandEmpty>
<CommandGroup heading="Navigation">
<CommandItem onSelect={() => navigate('/home')}>
<HomeIcon /> Home
</CommandItem>
</CommandGroup>
</CommandList>
</CommandDialog>tsx
<CommandDialog open={open} onOpenChange={setOpen}>
<CommandInput placeholder="Type a command..." />
<CommandList>
<CommandEmpty>No results found.</CommandEmpty>
<CommandGroup heading="Navigation">
<CommandItem onSelect={() => navigate('/home')}>
<HomeIcon /> Home
</CommandItem>
</CommandGroup>
</CommandList>
</CommandDialog>Keyboard Shortcuts
键盘快捷键
Standard bindings:
- /
Cmd+K- Open/close (standard convention)Ctrl+K - - Open (when not in input field)
/ - - Close
Escape - Arrow keys - Navigate
- - Select
Enter
Implementation:
tsx
useEffect(() => {
const handler = (e: KeyboardEvent) => {
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
e.preventDefault();
setOpen(prev => !prev);
}
if (e.key === '/' && !isInputFocused(e.target)) {
e.preventDefault();
setOpen(true);
}
};
document.addEventListener('keydown', handler);
return () => document.removeEventListener('keydown', handler);
}, []);
function isInputFocused(target: EventTarget | null): boolean {
return target instanceof HTMLElement &&
['INPUT', 'TEXTAREA', 'SELECT'].includes(target.tagName);
}标准绑定:
- /
Cmd+K- 打开/关闭(通用惯例)Ctrl+K - - 打开(未聚焦输入框时)
/ - - 关闭
Escape - 方向键 - 导航
- - 选择
Enter
实现代码:
tsx
useEffect(() => {
const handler = (e: KeyboardEvent) => {
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
e.preventDefault();
setOpen(prev => !prev);
}
if (e.key === '/' && !isInputFocused(e.target)) {
e.preventDefault();
setOpen(true);
}
};
document.addEventListener('keydown', handler);
return () => document.removeEventListener('keydown', handler);
}, []);
function isInputFocused(target: EventTarget | null): boolean {
return target instanceof HTMLElement &&
['INPUT', 'TEXTAREA', 'SELECT'].includes(target.tagName);
}Search Index Patterns
搜索索引模式
Static sites:
- Build index at compile time
- Pass as props to component
Dynamic:
- Fetch on mount or use server action
Structure:
typescript
interface SearchItem {
title: string;
description?: string;
href: string;
type: string; // e.g., "page", "blog", "command"
keywords?: string[];
}cmdk search:
- Searches the prop on
valueCommandItem - Include searchable text in value:
value={title + ' ' + keywords?.join(' ')}
静态站点:
- 在编译时构建索引
- 作为props传递给组件
动态站点:
- 在挂载时获取数据或使用服务器操作
索引结构:
typescript
interface SearchItem {
title: string;
description?: string;
href: string;
type: string; // e.g., "page", "blog", "command"
keywords?: string[];
}cmdk搜索逻辑:
- 搜索上的
CommandItem属性value - 将可搜索文本包含在value中:
value={title + ' ' + keywords?.join(' ')}
Styling Customization
样式自定义
Height:
tsx
<CommandList className="max-h-[300px]">Dialog position:
- Centered by default via
DialogContent
Item states:
tsx
<CommandItem className="data-[selected=true]:bg-accent">高度设置:
tsx
<CommandList className="max-h-[300px]">对话框位置:
- 默认通过居中显示
DialogContent
项目状态样式:
tsx
<CommandItem className="data-[selected=true]:bg-accent">Accessibility
无障碍支持
Built-in:
- Focus trap (Radix Dialog)
- Escape/click-outside handling
- Arrow navigation (cmdk)
- Screen reader announcements
Ensure:
- Visible focus indicators
- Meaningful item labels
- Icon-only items have aria-label
内置特性:
- 焦点陷阱(Radix Dialog)
- 按Esc/点击外部关闭的处理
- 方向键导航(cmdk)
- 屏幕阅读器播报
需确保:
- 可见的焦点指示器
- 有意义的项目标签
- 仅图标项目带有aria-label
External Resources
外部资源
- cmdk docs: https://cmdk.paco.me/
- shadcn Command: https://ui.shadcn.com/docs/components/command
- Radix Dialog: https://www.radix-ui.com/primitives/docs/components/dialog
- cmdk文档:https://cmdk.paco.me/
- shadcn Command组件:https://ui.shadcn.com/docs/components/command
- Radix Dialog:https://www.radix-ui.com/primitives/docs/components/dialog