Skip to content

Controlled Dialog ​

Command.Dialog opens when its open prop becomes true and closes when it becomes false. Escape and overlay clicks close the dialog and then call onOpenChange(false), so pass your setter (onOpenChange={setOpen}) to keep your state in step. Without open, nothing opens the dialog.

Controlled Mode ​

Pass open and onOpenChange to control the dialog state:

tsx
import { Command } from 'modern-cmdk/react';
import { useState } from 'react';

function App() {
  const [open, setOpen] = useState(false);

  return (
    <>
      <button onClick={() => setOpen(true)}>Open Commands</button>
      <Command.Dialog open={open} onOpenChange={setOpen}>
        <Command.Input />
        <Command.List>
          <Command.Item value="close" onSelect={() => setOpen(false)}>Close</Command.Item>
        </Command.List>
      </Command.Dialog>
    </>
  );
}

URL-Driven State ​

Sync dialog state with URL search params:

tsx
'use client';

import { Command } from 'modern-cmdk/react';
import { useRouter, useSearchParams } from 'next/navigation';

function CommandPalette() {
  const router = useRouter();
  const params = useSearchParams();
  const open = params.get('cmd') === '1';

  return (
    <Command.Dialog
      open={open}
      onOpenChange={(isOpen: boolean) => {
        const next = new URLSearchParams(params);
        if (isOpen) next.set('cmd', '1');
        else next.delete('cmd');
        router.replace(`?${next.toString()}`);
      }}
    >
      <Command.Input placeholder="Search commands..." />
      <Command.List>{/* command items */}</Command.List>
    </Command.Dialog>
  );
}

Multiple Palettes ​

Use separate Command.Dialog components, each with its own open state — each creates its own state machine:

tsx
import { Command } from 'modern-cmdk/react';
import { useState } from 'react';

function Palettes() {
  const [commandsOpen, setCommandsOpen] = useState(false);
  const [settingsOpen, setSettingsOpen] = useState(false);

  return (
    <>
      <Command.Dialog open={commandsOpen} onOpenChange={setCommandsOpen}> {/* Main palette */}
        <Command.Input placeholder="Search commands..." />
        <Command.List>{/* command items */}</Command.List>
      </Command.Dialog>

      <Command.Dialog open={settingsOpen} onOpenChange={setSettingsOpen}> {/* Settings palette */}
        <Command.Input placeholder="Search settings..." />
        <Command.List>{/* settings items */}</Command.List>
      </Command.Dialog>
    </>
  );
}