Command palette
⌘K search for pages, people and actions.
Built with
- Button
- CommandPalette
- CommandPaletteItem
- CommandPaletteSection
Northwind
Jump anywhere
Use the search button, or press ⌘K (Ctrl K) while focus is in this screen, to find a page, start a request or open someone's profile.
Nothing opened yet.
command-palette.tsx
"use client";
import { useState, type Key, type KeyboardEvent } from "react";
import {
LuCalendarDays,
LuCalendarPlus,
LuClipboardCheck,
LuSearch,
LuSettings,
LuUser,
LuUserPlus,
LuWallet,
} from "react-icons/lu";
import {
Button,
CommandPalette,
CommandPaletteItem,
CommandPaletteSection,
} from "@nexera-ui/react";
// Sample data
interface Person {
id: string;
name: string;
initials: string;
role: string;
team: string;
email: string;
location: string;
status: "Active" | "On leave" | "Remote" | "Invited";
}
const PEOPLE: Person[] = [
{
id: "p1",
name: "Ayesha Khan",
initials: "AK",
role: "Senior product designer",
team: "Design",
email: "ayesha.khan@northwind.io",
location: "London",
status: "Active",
},
{
id: "p2",
name: "Sara Malik",
initials: "SM",
role: "Payroll specialist",
team: "People Ops",
email: "sara.malik@northwind.io",
location: "Lisbon",
status: "On leave",
},
{
id: "p3",
name: "Ahmed Raza",
initials: "AR",
role: "Engineering manager",
team: "Engineering",
email: "ahmed.raza@northwind.io",
location: "Lahore",
status: "Remote",
},
{
id: "p4",
name: "Mia Jensen",
initials: "MJ",
role: "Product manager",
team: "Product",
email: "mia.jensen@northwind.io",
location: "Copenhagen",
status: "Active",
},
{
id: "p5",
name: "Luis Ortega",
initials: "LO",
role: "Frontend engineer",
team: "Engineering",
email: "luis.ortega@northwind.io",
location: "Madrid",
status: "Active",
},
{
id: "p6",
name: "Yuki Tanaka",
initials: "YT",
role: "Recruiter",
team: "People Ops",
email: "yuki.tanaka@northwind.io",
location: "Tokyo",
status: "Active",
},
{
id: "p7",
name: "Chloe Martin",
initials: "CM",
role: "Data analyst",
team: "Finance",
email: "chloe.martin@northwind.io",
location: "Paris",
status: "Remote",
},
{
id: "p8",
name: "Omar Haddad",
initials: "OH",
role: "Support lead",
team: "Customer",
email: "omar.haddad@northwind.io",
location: "Dubai",
status: "Invited",
},
];
const LABELS: Record<string, string> = {
calendar: "Leave calendar",
approvals: "Approvals",
payroll: "Payroll runs",
request: "Request leave",
invite: "Invite a person",
settings: "Workspace settings",
...Object.fromEntries(PEOPLE.map((person) => [person.id, person.name])),
};
/** Command palette: ⌘K (or Ctrl K) search across pages, actions and people. */
export default function CommandPaletteBlock() {
const [isOpen, setOpen] = useState(false);
const [last, setLast] = useState<string | null>(null);
// ⌘K / Ctrl K toggles the palette. Scoped to this screen so it does not clash with the docs site's own ⌘K;
// in your app, listen on `window` instead.
const onKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
if (event.key.toLowerCase() === "k" && (event.metaKey || event.ctrlKey)) {
event.preventDefault();
event.stopPropagation();
setOpen((open) => !open);
}
};
const onAction = (key: Key) => {
setLast(LABELS[String(key)] ?? String(key));
};
return (
// eslint-disable-next-line jsx-a11y/no-static-element-interactions -- shortcut scope, not a control: catches ⌘K bubbling from this screen and its portalled palette
<div className="@container bg-page px-4 py-8 @3xl:px-8" onKeyDown={onKeyDown}>
<div className="mx-auto grid max-w-3xl gap-6">
<header className="flex flex-wrap items-center justify-between gap-3 rounded-xl border border-default bg-surface px-4 py-3 shadow-xs">
<h2 className="text-heading-h4 text-primary">Northwind</h2>
<CommandPalette
isOpen={isOpen}
onOpenChange={setOpen}
onAction={onAction}
searchLabel="Search Northwind"
hints={[
{ keys: "↑↓", label: "navigate" },
{ keys: "↵", label: "open" },
{ keys: "⌘K", label: "toggle" },
]}
trigger={
<Button
variant="secondary"
size="md"
leadingIcon={<LuSearch />}
aria-keyshortcuts="Meta+K Control+K"
>
Search people, pages and actions
</Button>
}
>
<CommandPaletteSection title="Pages">
<CommandPaletteItem
id="calendar"
label="Leave calendar"
icon={<LuCalendarDays />}
shortcut="G L"
/>
<CommandPaletteItem
id="approvals"
label="Approvals"
icon={<LuClipboardCheck />}
shortcut="G A"
/>
<CommandPaletteItem
id="payroll"
label="Payroll runs"
icon={<LuWallet />}
shortcut="G P"
/>
</CommandPaletteSection>
<CommandPaletteSection title="Actions">
<CommandPaletteItem
id="request"
label="Request leave"
icon={<LuCalendarPlus />}
shortcut="N L"
/>
<CommandPaletteItem
id="invite"
label="Invite a person"
icon={<LuUserPlus />}
shortcut="N P"
/>
<CommandPaletteItem id="settings" label="Workspace settings" icon={<LuSettings />} />
</CommandPaletteSection>
<CommandPaletteSection title="People">
{PEOPLE.slice(0, 5).map((person) => (
<CommandPaletteItem
key={person.id}
id={person.id}
label={`${person.name} · ${person.role}`}
textValue={`${person.name} ${person.role} ${person.team}`}
icon={<LuUser />}
/>
))}
</CommandPaletteSection>
</CommandPalette>
</header>
<section
aria-labelledby="command-palette-tips"
className="grid gap-3 rounded-xl border border-default bg-surface p-6"
>
<h3 id="command-palette-tips" className="text-heading-h4 text-primary">
Jump anywhere
</h3>
<p className="text-body-default text-secondary">
Use the search button, or press{" "}
<kbd className="rounded-sm border border-default bg-sunken px-1.5 text-body-small">
⌘K
</kbd>{" "}
(
<kbd className="rounded-sm border border-default bg-sunken px-1.5 text-body-small">
Ctrl K
</kbd>
) while focus is in this screen, to find a page, start a request or open someone's
profile.
</p>
<p className="text-body-small text-secondary" role="status">
{last ? `Opened: ${last}` : "Nothing opened yet."}
</p>
</section>
</div>
</div>
);
}
More app shells and navigation blocks
- Sidebar app shellSidebar with sections, nested items, badges and a user card.
- Top bar with tabsPage title, breadcrumbs, actions and section tabs.
- Mobile app shellTop app bar and a bottom navigation bar.
- Settings layoutVertical tabs on the left, a form on the right.
- Page headerTitle, description, status badge and primary actions.
- Workspace switcherSwitch organisation or create a new one.