Dialog
A complete command palette dialog triggered by Cmd+K (Mac) / Ctrl+K (Windows/Linux), with @starting-style enter/exit animations (until the dialog-token fix ships in 1.8.0, set the animation tokens on [data-command-dialog] and [data-command-overlay]; see Theming).
tsx
'use client';
import { Command } from 'modern-cmdk/react';
import { useEffect, useState } from 'react';
export function DialogExample() {
const [open, setOpen] = useState(false);
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'k' && (e.metaKey || e.ctrlKey)) {
e.preventDefault();
setOpen((prev) => !prev);
}
};
document.addEventListener('keydown', handleKeyDown);
return () => document.removeEventListener('keydown', handleKeyDown);
}, []);
return (
<>
<button onClick={() => setOpen(true)}>
Open Command Palette
<kbd>Cmd+K</kbd>
</button>
<Command.Dialog
open={open}
onOpenChange={setOpen}
label="Command Menu"
>
<Command.Input placeholder="What do you need?" />
<Command.List>
<Command.Loading>Searching...</Command.Loading>
<Command.Empty>No results found.</Command.Empty>
<Command.Group heading="Navigation">
<Command.Item value="home" onSelect={() => setOpen(false)}>
Home
</Command.Item>
<Command.Item value="dashboard" onSelect={() => setOpen(false)}>
Dashboard
</Command.Item>
<Command.Item value="settings" onSelect={() => setOpen(false)}>
Settings
<Command.Shortcut shortcut="Mod+," />
</Command.Item>
</Command.Group>
<Command.Separator />
<Command.Group heading="Actions">
<Command.Item value="new-project" onSelect={() => setOpen(false)}>
New Project
<Command.Shortcut shortcut="Mod+N" />
</Command.Item>
<Command.Item value="invite-member" onSelect={() => setOpen(false)}>
Invite Team Member
</Command.Item>
<Command.Item value="export" onSelect={() => setOpen(false)}>
Export Data
<Command.Shortcut shortcut="Mod+Shift+E" />
</Command.Item>
</Command.Group>
</Command.List>
</Command.Dialog>
</>
);
}Animation CSS
The dialog uses @starting-style for its enter animation and transition-behavior: allow-discrete for its exit animation; until 1.8.0 the tokens it reads must be set outside [data-command-root] (see Theming):
css
/* Enter -- spring easing via linear() */
[data-command-dialog][data-state="open"] {
@starting-style {
opacity: 0;
scale: 0.96;
translate: 0 8px;
}
opacity: 1;
scale: 1;
translate: 0 0;
transition:
opacity 200ms var(--ease-out-expo),
scale 250ms var(--ease-spring),
translate 250ms var(--ease-spring),
display 250ms allow-discrete,
overlay 250ms allow-discrete;
}
/* Exit -- quick fade without spring overshoot */
[data-command-dialog][data-state="closed"] {
opacity: 0;
scale: 0.96;
translate: 0 4px;
transition:
opacity 150ms cubic-bezier(0.4, 0, 1, 1),
scale 150ms cubic-bezier(0.4, 0, 1, 1),
translate 150ms cubic-bezier(0.4, 0, 1, 1),
display 150ms allow-discrete,
overlay 150ms allow-discrete;
}
/* Overlay backdrop */
[data-command-overlay][data-state="open"] {
@starting-style {
opacity: 0;
}
opacity: 1;
background: oklch(0 0 0 / 0.4);
backdrop-filter: blur(4px);
transition: opacity 200ms var(--ease-out-expo);
}TIP
All animations respect prefers-reduced-motion: reduce. When the user prefers reduced motion, transitions complete instantly.