Command Palette

@sushindustries/ui

Search over everything the host can name, in a native dialog: substring filter, arrow keys, and the host keeps the router.

6 min read
View as MarkdownEdit on GitHub

Examples are the tab where the component is shown doing a job, not demonstrating a prop. The API tab already lists the props.

Viewport width
Phone22remthe floor, the narrowest this promises to work at
tanstacktanstack add https://adamjurek.com/r/tanstack/command-palette.jsonshadcnpnpm dlx shadcn@latest add https://adamjurek.com/r/shadcn/command-palette.json

Press Compare. The frames are real viewports, so a layout that breaks at 320 breaks here too rather than in somebody's hands.

In a page

import { useEffect, useState } from "react";
import { useNavigate } from "@tanstack/react-router";
import { CommandPalette } from "@sushindustries/ui";
import { searchEntries } from "./search.catalogue";

export function SiteChrome({ children }: { children: React.ReactNode }) {
	const [open, setOpen] = useState(false);
	const navigate = useNavigate();

	useEffect(() => {
		function onKeyDown(event: KeyboardEvent) {
			if (event.key === "k" && (event.metaKey || event.ctrlKey)) {
				event.preventDefault();
				setOpen(true);
			}
		}
		window.addEventListener("keydown", onKeyDown);
		return () => window.removeEventListener("keydown", onKeyDown);
	}, []);

	return (
		<>
			{children}
			<CommandPalette
				entries={searchEntries}
				open={open}
				onClose={() => setOpen(false)}
				onSelect={(entry) => {
					setOpen(false);
					navigate({ to: entry.href });
				}}
			/>
		</>
	);
}
tsx

What this example is not

The ⌘K listener here is the host's own effect, not something CommandPalette sets up for you - the component only reacts to open. navigate from the router replaces the plain window.location write from Get Started, which is the difference between a full page load and a client-side transition.

UsesIconIconThe glyph set, generated from a Markdown table where every drawing carries its reason. One component, typed names, no icon font.@sushindustries/ui · content