Recipes
05

CommandPalette

⌘K search over a command list — a real listbox with full keyboard navigation.

rendered by aura-react
rendered by aura-react
rendered by aura-react
rendered by aura-react
rendered by aura-react

Code

Demo.tsx
import { useMemo, useState } from 'react';
import { Button, Dialog, Field, Typography } from '@ilomee/aura-react';

const COMMANDS = [
  { id: 'theme', label: 'Toggle theme' },
  { id: 'accent', label: 'Change accent', description: '10 to choose from' },
  { id: 'docs', label: 'Open docs' },
];

// A palette is a Dialog, a Field and a list you filter. `Dialog` brings the scrim, the trap and
// Escape; `Select`'s own listbox brings the keyboard when the list has to be arrowed through.
// This is the shape, not a component: what a palette *does* is your commands.
export default function Demo() {
  const [open, setOpen] = useState(true);
  const [query, setQuery] = useState('');
  const shown = useMemo(
    () => COMMANDS.filter((c) => c.label.toLowerCase().includes(query.toLowerCase())),
    [query],
  );

  return (
    <>
      <Button variant="primary" onClick={() => setOpen(true)}>
        Open palette
      </Button>
      <Dialog open={open} onClose={() => setOpen(false)} label="Commands" top autoFocus={false}>
        <Field label="Command" value={query} onValueChange={setQuery} placeholder="Type a command…" />
        <ul className="aura-listbox" role="listbox" aria-label="Commands" style={{ marginTop: 12 }}>
          {shown.map((command) => (
            <li key={command.id} className="aura-listbox__option" role="option" aria-selected="false">
              <span className="aura-listbox__label">
                {command.label}
                {command.description && (
                  <span className="aura-listbox__description">{command.description}</span>
                )}
              </span>
            </li>
          ))}
          {shown.length === 0 && <li className="aura-listbox__empty">Nothing matches.</li>}
        </ul>
        <Typography variant="caption" tone="faint" style={{ marginTop: 12 }}>
          Wire ⌘K to `setOpen(true)` — the shortcut is the app's, not the dialog's.
        </Typography>
      </Dialog>
    </>
  );
}

This is an example, not a component — no package ships it, and there is nothing to import. It is built from primitives that each of the four packages does ship, so the same composition works in every stack; copy it into your own component and it is yours to change.

Props

No props: the composition takes what you give the primitives inside it. Their props are on their own pages.

Emitted classes

Every framework emits the same classes — that is what makes the four libraries look identical. You can use them directly, without any component library.

ClassRoleNotes
.aura-overlaybaseRequired. A modifier does nothing without it.
.aura-popupbaseRequired. A modifier does nothing without it.