Advanced
stable
Command Palette
Command Palette: Keyboard-driven search and action launcher.
Preview
Command Palette
Global search entrypoint preview. The full site command palette is also available from the navbar.
Import
tsx
import { CommandPalette } from "@/components/ui/command-palette";bash
npx sui add command-paletteSource
From components/ui/command-palette.tsx
tsx
// @ts-nocheck
import React, { useEffect, useMemo, useState } from "react";
import { Command } from "cmdk";
import { Search, Blocks, BookOpen, Box, Component, Layers } from "lucide-react";
import { motion, AnimatePresence } from "motion/react";
import { useNavigate } from "react-router-dom";
import { getAllComponents } from "@/src/lib/registry";
export const CommandPalette = () => {
const [open, setOpen] = useState(false);
const navigate = useNavigate();
const components = useMemo(() => getAllComponents(), []);
const goTo = (href: string): void => {
navigate(href);
setOpen(false);
};
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 (
<>
<button
onClick={() => setOpen(true)}
className="flex items-center gap-2 px-3 py-1.5 text-sm text-muted-foreground border rounded-lg bg-muted/50 hover:bg-muted transition-colors"
>
<Search className="h-4 w-4" />
<span>Search...</span>
<kbd className="pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground opacity-100">
<span className="text-xs">⌘</span>K
</kbd>
</button>
<AnimatePresence>
{open && (
<div className="fixed inset-0 z-50 flex items-start justify-center pt-[20vh] p-4">
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={() => setOpen(false)}
className="fixed inset-0 bg-background/80 backdrop-blur-sm"
/>
<motion.div
initial={{ opacity: 0, scale: 0.95, y: -20 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.95, y: -20 }}
className="relative w-full max-w-2xl overflow-hidden rounded-xl border bg-popover shadow-2xl"
>
<Command className="flex h-full w-full flex-col overflow-hidden">
<div className="flex items-center border-b px-3">
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
<Command.Input
placeholder="Type a command or search..."
className="flex h-12 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50"
/>
</div>
<Command.List className="max-h-[300px] overflow-y-auto overflow-x-hidden p-2">
<Command.Empty className="py-6 text-center text-sm">No results found.</Command.Empty>
<Command.Group heading="Jump to" className="px-2 py-1.5 text-xs font-medium text-muted-foreground">
<CommandItem icon={<BookOpen />} label="Docs" onSelect={() => goTo("/docs")} />
<CommandItem icon={<Component />} label="Components" onSelect={() => goTo("/components")} />
<CommandItem icon={<Blocks />} label="Blocks" onSelect={() => goTo("/blocks")} />
</Command.Group>
<Command.Separator className="-mx-2 my-1 h-px bg-border" />
<Command.Group heading="Registry Components" className="px-2 py-1.5 text-xs font-medium text-muted-foreground">
{components.map((component) => (
<Command.Item
key={component.id}
value={component.title}
onSelect={() => goTo(`/components/${component.slug}`)}
className="relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50"
>
<div className="mr-2 flex h-4 w-4 items-center justify-center opacity-70">
{component.category === "Data Display" ? <Layers className="h-4 w-4" /> : <Box className="h-4 w-4" />}
</div>
<span>{component.title}</span>
<span className="ml-auto text-xs tracking-widest text-muted-foreground">
{component.category}
</span>
</Command.Item>
))}
</Command.Group>
</Command.List>
</Command>
</motion.div>
</div>
)}
</AnimatePresence>
</>
);
};
interface CommandItemProps {
icon: React.ReactNode;
label: string;
meta?: string;
onSelect?: () => void;
}
const CommandItem = ({ icon, label, meta, onSelect }: CommandItemProps) => (
<Command.Item
value={label}
onSelect={onSelect}
className="relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50"
>
<div className="mr-2 flex h-4 w-4 items-center justify-center opacity-70">
{icon}
</div>
<span>{label}</span>
{meta && (
<span className="ml-auto text-xs tracking-widest text-muted-foreground">
{meta}
</span>
)}
</Command.Item>
);
Component Info
Slug
command-paletteCategory
Advanced
Status
stable
Quick Actions