Command Palette
beui/command-paletteFreeBlock
⌘K palette with fuzzy filter, spring-animated active row and glass surface.
Install it
npx shadcn@latest add https://beui.dev/r/command-palette.jsonSource
1"use client";2// beui.dev/components/blocks/command-palette34import { motion, useReducedMotion } from "motion/react";5import { Search, type LucideIcon } from "lucide-react";6import {7 type ReactNode,8 useCallback,9 useEffect,10 useId,11 useMemo,12 useRef,13 useState,14} from "react";15import { createPortal } from "react-dom";16import { EASE_OUT } from "@/lib/ease";17import { cn } from "@/lib/utils";1819export type CommandItem = {20 id: string;21 label: string;22 group?: string;23 hint?: string;24 keywords?: string[];25 icon?: LucideIcon;26 badge?: ReactNode;27 onSelect: () => void;28};2930export interface CommandPaletteProps {31 items: CommandItem[];32 /** Opens with Cmd/Ctrl + this key. Default: "k" */33 shortcut?: string;34 placeholder?: string;35 emptyMessage?: string;36 open?: boolean;37 onOpenChange?: (open: boolean) => void;38}3940function fuzzyMatch(needle: string, hay: string) {41 if (!needle) return true;42 needle = needle.toLowerCase();43 hay = hay.toLowerCase();44 let i = 0;45 for (const ch of hay) {46 if (ch === needle[i]) i++;47 if (i === needle.length) return true;48 }49 return false;50}5152// Opened via a keyboard shortcut many times a day — entrance must read as53// instant. Tight spring, even faster exit.54const PANEL_SPRING = {55 type: "spring",56 stiffness: 560,57 damping: 40,58 mass: 0.5,59} as const;6061export function CommandPalette({62 items,63 shortcut = "k",64 placeholder = "Type a command or search…",65 emptyMessage = "No results found.",66 open: controlledOpen,67 onOpenChange,68}: CommandPaletteProps) {69 const [internalOpen, setInternalOpen] = useState(false);70 const controlled = controlledOpen !== undefined;71 const open = controlled ? controlledOpen : internalOpen;72 const setOpen = useCallback(73 (v: boolean) => {74 if (!controlled) setInternalOpen(v);75 onOpenChange?.(v);76 },77 [controlled, onOpenChange],78 );7980 const [query, setQuery] = useState("");81 const [active, setActive] = useState(0);82 // Portal target only exists client-side; render nothing during SSR/hydration.83 const [mounted, setMounted] = useState(false);84 useEffect(() => setMounted(true), []);85 const uid = useId();86 const reduce = useReducedMotion();87 const updateQuery = useCallback((value: string) => {88 setQuery(value);89 setActive(0);90 }, []);91 const inputRef = useRef<HTMLInputElement>(null);92 const listRef = useRef<HTMLDivElement>(null);9394 useEffect(() => {95 const onKey = (e: KeyboardEvent) => {96 if (97// … truncated
What it pulls in
npm packages
Files it writes
More from beui
All 104 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| File Upload Attachment Uploadattachment-upload | beui | Blocks | Free | 4 deps · 5 files | |
| Availability Scheduleravailability-scheduler | beui | Blocks | Free | 4 deps · 15 files | |
| Bloom Menubloom-menu | beui | Blocks | Free | 4 deps · 3 files | |
| Dynamic Islanddynamic-island | beui | Blocks | Free | 3 deps · 3 files | |
| Expandable Action Barexpandable-action-bar | beui | Blocks | Free | 3 deps · 2 files | |
| Expandable Tabsexpandable-tabs | beui | Blocks | Free | 3 deps · 3 files | |
| Feedback Widgetfeedback-widget | beui | Blocks | Free | 4 deps · 9 files | |
| File Upload Upload Queuefile-upload | beui | Blocks | Free | 4 deps · 3 files |
