命令菜单
一个移动端友好的命令面板,用于搜索和快速操作。
基于以下组件构建:
安装
pnpm dlx shadcn@latest add @lumi-ui/command-menu
组件结构
<CommandMenu>
<CommandMenuTrigger />
<CommandMenuContent>
<Command items={groupedItems}>
<CommandInput />
<CommandEmpty />
<CommandScrollArea>
<CommandList>
<CommandGroup>
<CommandGroupLabel />
<CommandCollection>
<CommandItem>
<CommandShortcut />
</CommandItem>
</CommandCollection>
</CommandGroup>
<CommandSeparator />
</CommandList>
</CommandScrollArea>
</Command>
<CommandMenuFooter />
</CommandMenuContent>
</CommandMenu>基本用法
"use client";
import * as React from "react";
import {
Command,
CommandCollection,
CommandEmpty,
CommandGroup,
CommandGroupLabel,
CommandInput,
CommandItem,
CommandList,
CommandMenu,
CommandMenuContent,
CommandMenuTrigger,
CommandScrollArea,
} from "@/components/ui/command-menu";
import { Button } from "@/components/ui/button";
export function CommandMenuMinimal() {
const [open, setOpen] = React.useState(false);
return (
<CommandMenu onOpenChange={setOpen} open={open}>
<CommandMenuTrigger render={<Button variant="outline">打开</Button>} />
<CommandMenuContent aria-label="命令菜单">
<Command items={groupedItems}>
<CommandInput placeholder="搜索..." />
<CommandEmpty>未找到结果。</CommandEmpty>
<CommandScrollArea>
<CommandList>
{(group: Group) => (
<CommandGroup items={group.items} key={group.value}>
<CommandGroupLabel>{group.value}</CommandGroupLabel>
<CommandCollection>
{(item: Item) => (
<CommandItem
key={item.value}
onClick={() => setOpen(false)}
value={item}
>
{item.label}
</CommandItem>
)}
</CommandCollection>
</CommandGroup>
)}
</CommandList>
</CommandScrollArea>
</Command>
</CommandMenuContent>
</CommandMenu>
);
}
type Item = { value: string; label: string };
type Group = { value: string; items: Item[] };
const groupedItems: Group[] = [
{
value: "资源",
items: [
{ label: "文档", value: "docs" },
{ label: "组件", value: "components" },
],
},
{
value: "操作",
items: [{ label: "设置", value: "settings" }],
},
];实用示例
下面这些自定义都在 components/ui/command-menu.tsx 中完成。
居中显示命令菜单
<DialogViewport
className={cn(
"flex flex-col items-center justify-center",
// 添加顶部内边距,让弹窗向下移动
"pt-[10dvh]",
)}
>调整位置
通过视口顶部内边距控制弹窗的高低位置:
pt-[20dvh]:更低pt-[10dvh]:默认pt-[5dvh]:更高
<DialogViewport className={cn("flex flex-col items-center", "pt-[10dvh]")} />调整弹窗宽度和动画
在 CommandMenuContent 中,下面这段类名控制宽度和默认动画:
"w-[min(40rem,calc(100vw-2rem))] animate-fade-zoom"w-[min(40rem,calc(100vw-2rem))]让菜单在移动端也保持良好显示。- 你可以把
animate-fade-zoom替换为 动画指南 中支持的任意工具类。
CommandScrollArea
默认的 CommandScrollArea 使用:
"h-auto max-h-64 sm:max-h-96"h-auto让内容高度自动适应。max-h-64是可选项,可以让列表显示得更短。
你也可以跳过 CommandScrollArea,使用自己的容器:
<div className="h-auto max-h-80 overflow-y-auto">
<CommandList>{/* 选项列表 */}</CommandList>
</div>替换输入框
CommandInput 基于 AutocompleteInputGroupContent 构建,可显示一个清除按钮(showClear)。
如果你需要完全的控制权,可以用 AutocompleteInput 替换它:
import { AutocompleteInput } from "@/components/ui/autocomplete";
<Command items={groupedItems}>
<AutocompleteInput className="border-b px-4 py-3" placeholder="搜索..." />
</Command>配合 TanStack Hotkeys 使用
调整 CommandItem 的高亮样式
CommandItem 使用了带内嵌定位的高亮类:
"group/command-item ... data-[highlighted]:before:inset-x-3"调整 inset 值(如 inset-x-2、inset-x-4 等),就能改变高亮“胶囊”的宽度,无需在父级列表容器上额外添加内边距。
更多细节请参阅 命中测试与高亮。
API 参考
CommandMenuContent
一个复合内容包装器,组合了 DialogPortal、DialogBackdrop、DialogViewport 和 DialogPopup。
Command
为命令交互预配置的 autocomplete 根组件。
CommandInput
一个基于 AutocompleteInputGroupContent 的复合输入框。
CommandScrollArea
命令结果的滚动容器。
CommandItem
带有内置高亮状态的命令行项。