XDSCommandPalette@xds/core · CommandPalette
Usage
CommandPalette is a searchable dialog for quick access to commands, navigation, and actions. Use it as a keyboard-driven launcher powered by XDSSearchSource for filtering and selection.Best practices
| Guidance | Practices |
|---|---|
| Do | Provide a searchSource with bootstrap results so users see useful options before typing. |
| Do | Use auxiliaryData.group on items to automatically organize results into labeled sections. |
| Don't | Use CommandPalette for simple dropdowns or menus — use XDSMenu or XDSSelector for inline selections. |
| Don't | Add too many groups or items — curate results to keep the palette fast and scannable. |
Import
tsimport {XDSCommandPalette} from '@xds/core/CommandPalette'
Props
| Prop | Type | Description |
|---|---|---|
isOpenrequired | boolean | Whether the command palette dialog is visible. |
onOpenChangerequired | (isOpen: boolean) => void | Called when the palette visibility changes. |
searchSourcerequired | XDSSearchSource<T> | Search source providing items via search(query) and bootstrap(). Use createStaticSource for static lists. |
input | ReactNode (default: <XDSCommandPaletteInput />) | Input slot. Defaults to XDSCommandPaletteInput with standard behavior. |
footer | ReactNode (default: <XDSCommandPaletteFooter />) | Footer slot. Defaults to XDSCommandPaletteFooter showing keyboard hints. |
renderItem | (item: T, isSelected: boolean) => ReactNode | Per-item render function. Auto-grouping by auxiliaryData.group is preserved. When omitted, renders label text. |
emptySearchText | ReactNode (default: 'No results') | Content shown when a search query returns no results. |
emptyBootstrapText | ReactNode (default: 'Type to search') | Content shown when there is no search query and bootstrap() returns nothing. |
value | string | Controlled selected value for picker mode. |
onValueChange | (value: string) => void | Called when the selected value changes in picker mode. |
label | string (default: 'Command palette') | Accessible label for the command palette dialog. |
width | number | string (default: 640) | Width of the dialog. |
maxHeight | number | string (default: 480) | Maximum height of the dialog. |
isInline | boolean (default: false) | Renders command palette content inline without modal behavior. For documentation previews and showcases only. |
Sub-components
CommandPalette is a compound component with 7 sub-components.XDSCommandPalette
Root component. Manages open state, search, keyboard navigation, and composition slots.| Prop | Type | Description |
|---|---|---|
isOpenrequired | boolean | Whether the command palette dialog is visible. |
onOpenChangerequired | (isOpen: boolean) => void | Called when the palette visibility changes. |
searchSourcerequired | XDSSearchSource<T> | Search source providing items via search(query) and bootstrap(). Use createStaticSource for static lists. |
input | ReactNode (default: <XDSCommandPaletteInput />) | Input slot. Defaults to XDSCommandPaletteInput with standard behavior. |
footer | ReactNode (default: <XDSCommandPaletteFooter />) | Footer slot. Defaults to XDSCommandPaletteFooter showing keyboard hints. |
renderItem | (item: T, isSelected: boolean) => ReactNode | Per-item render function. Auto-grouping by auxiliaryData.group is preserved. When omitted, renders label text. |
emptySearchText | ReactNode (default: 'No results') | Content shown when a search query returns no results. |
emptyBootstrapText | ReactNode (default: 'Type to search') | Content shown when there is no search query and bootstrap() returns nothing. |
value | string | Controlled selected value for picker mode. |
onValueChange | (value: string) => void | Called when the selected value changes in picker mode. |
label | string (default: 'Command palette') | Accessible label for the command palette dialog. |
width | number | string (default: 640) | Width of the dialog. |
maxHeight | number | string (default: 480) | Maximum height of the dialog. |
isInline | boolean (default: false) | Renders command palette content inline without modal behavior. For documentation previews and showcases only. |
XDSCommandPaletteEmpty
Empty state display for the results area. Rendered automatically by XDSCommandPalette for no-results and no-query states.| Prop | Type | Description |
|---|---|---|
childrenrequired | ReactNode | Message or content to display. |
XDSCommandPaletteFooter
Footer showing keyboard navigation hints. Renders default arrow/Enter/Escape hints when no children are provided.| Prop | Type | Description |
|---|---|---|
children | ReactNode | Custom footer content. When omitted, renders default keyboard hints via XDSKbd. |
xstyle | StyleXStyles | StyleX styles for layout customization. Must be a stylex.create() value. |
XDSCommandPaletteGroup
Visual grouping with a heading label. Place inside XDSCommandPaletteList.| Prop | Type | Description |
|---|---|---|
headingrequired | string | Group heading text. |
childrenrequired | ReactNode | XDSCommandPaletteItem children. |
xstyle | StyleXStyles | StyleX styles for layout customization. Must be a stylex.create() value. |
XDSCommandPaletteInput
Search input slot. Auto-focuses on mount. Wires to command palette context when used inside XDSCommandPalette.| Prop | Type | Description |
|---|---|---|
placeholder | string (default: 'Search...') | Placeholder text for the input. |
hasAutoFocus | boolean (default: true) | Auto-focus the input when mounted. |
endContent | ReactNode | Content rendered at the trailing end of the input, after the spinner. Use for clear buttons or keyboard shortcut hints. |
value | string | Search value. When omitted inside XDSCommandPalette, reads from context. |
onValueChange | (value: string) => void | Called when search value changes. When omitted inside XDSCommandPalette, writes to context. |
xstyle | StyleXStyles | StyleX styles for layout customization. Must be a stylex.create() value. |
XDSCommandPaletteItem
A selectable item. Accepts arbitrary children for full rendering control. Registers with context for keyboard navigation when inside XDSCommandPalette.| Prop | Type | Description |
|---|---|---|
valuerequired | string | Unique value for identification and selection. |
childrenrequired | ReactNode | Item content — render icons, descriptions, keyboard shortcuts, etc. |
onSelect | (value: string) => void | Called when this item is selected via click or Enter. |
isHighlighted | boolean (default: false) | Whether this item has keyboard focus. Derived from context when inside XDSCommandPalette. |
isSelected | boolean (default: false) | Whether this item is selected in picker mode. |
isDisabled | boolean (default: false) | Whether the item is non-interactive. |
xstyle | StyleXStyles | StyleX styles for layout customization. Must be a stylex.create() value. |
XDSCommandPaletteList
Scrollable results container. Renders as a listbox for ARIA. Contains XDSCommandPaletteItem and XDSCommandPaletteGroup children.| Prop | Type | Description |
|---|---|---|
childrenrequired | ReactNode | Items, groups, and empty states. |
label | string (default: 'Commands') | Accessible label for the listbox. |
xstyle | StyleXStyles | StyleX styles for layout customization. Must be a stylex.create() value. |
Examples
Common configurations, variations, and states.CommandPalette — Async SearchServer-side search with loading spinner and custom empty states.
tsx'use client';import {useMemo} from 'react';import {XDSCommandPalette,XDSCommandPaletteInput,} from '@xds/core/CommandPalette';import type {XDSSearchSource} from '@xds/core/Typeahead';const allFiles = [{id: 'readme', label: 'README.md'},{id: 'package', label: 'package.json'},{id: 'tsconfig', label: 'tsconfig.json'},{id: 'index', label: 'src/index.ts'},{id: 'app', label: 'src/App.tsx'},];export default function CommandPaletteAsyncSearch() {const source = useMemo<XDSSearchSource>(() => ({async search(query: string) {await new Promise(r => setTimeout(r, 400));return allFiles.filter(f =>f.label.toLowerCase().includes(query.toLowerCase()),);},bootstrap() {return [];},}),[],);return (<XDSCommandPaletteisOpenisInlineonOpenChange={() => {}}searchSource={source}input={<XDSCommandPaletteInput placeholder="Search files..." />}emptyBootstrapText="Type a filename to search"emptySearchText="No files found"/>);}
CommandPalette — Custom FooterCommand palette with a custom footer tip message.
tsx'use client';import {useMemo} from 'react';import {XDSCommandPalette,XDSCommandPaletteFooter,} from '@xds/core/CommandPalette';import {XDSText} from '@xds/core/Text';import {createStaticSource} from '@xds/core/Typeahead';export default function CommandPaletteCustomFooter() {const source = useMemo(() =>createStaticSource([{id: 'home', label: 'Home'},{id: 'settings', label: 'Settings'},]),[],);return (<XDSCommandPaletteisOpenisInlineonOpenChange={() => {}}searchSource={source}footer={<XDSCommandPaletteFooter><XDSText type="supporting">Pro tip: use ⌘K to open anywhere</XDSText></XDSCommandPaletteFooter>}/>);}
CommandPalette — GroupedCommand palette with items grouped via auxiliaryData.group.
tsx'use client';import {useMemo} from 'react';import {XDSCommandPalette} from '@xds/core/CommandPalette';import {createStaticSource} from '@xds/core/Typeahead';export default function CommandPaletteAutoGrouped() {const source = useMemo(() =>createStaticSource([{id: 'home', label: 'Home', auxiliaryData: {group: 'Navigation'}},{id: 'settings',label: 'Settings',auxiliaryData: {group: 'Navigation'},},{id: 'new-file', label: 'New File', auxiliaryData: {group: 'Actions'}},{id: 'save', label: 'Save', auxiliaryData: {group: 'Actions'}},]),[],);return (<XDSCommandPaletteisOpenisInlineonOpenChange={() => {}}searchSource={source}/>);}
CommandPalette — Picker ModeSingle-value picker with persistent selection and check indicator.
tsx'use client';import {useState, useMemo} from 'react';import {XDSCommandPalette} from '@xds/core/CommandPalette';import {XDSText} from '@xds/core/Text';import {XDSIcon} from '@xds/core/Icon';import {createStaticSource} from '@xds/core/Typeahead';export default function CommandPalettePickerMode() {const [theme, setTheme] = useState('light');const source = useMemo(() =>createStaticSource([{id: 'light', label: 'Light'},{id: 'dark', label: 'Dark'},{id: 'system', label: 'System'},]),[],);return (<XDSCommandPaletteisOpenisInlineonOpenChange={() => {}}searchSource={source}value={theme}onValueChange={setTheme}renderItem={(item, isSelected) => (<><XDSText type="body" style={{flex: 1}}>{item.label}</XDSText>{isSelected && <XDSIcon icon="check" size="sm" />}</>)}/>);}
CommandPalette — Rich ItemsCustom item rendering with icons, keyboard shortcuts, and keyword search.
tsx'use client';import {useMemo} from 'react';import {XDSCommandPalette} from '@xds/core/CommandPalette';import {XDSText} from '@xds/core/Text';import {XDSKbd} from '@xds/core/Kbd';import {createStaticSource} from '@xds/core/Typeahead';import type {XDSSearchableItem} from '@xds/core/Typeahead';type RichCommand = XDSSearchableItem<{group?: string;shortcut?: string;}>;const commands: RichCommand[] = [{id: 'settings',label: 'Open Settings',auxiliaryData: {group: 'Navigation', shortcut: 'mod+,'},},{id: 'profile',label: 'View Profile',auxiliaryData: {group: 'Navigation'},},{id: 'new-file',label: 'Create New File',auxiliaryData: {group: 'Actions', shortcut: 'mod+n'},},{id: 'search',label: 'Search Files',auxiliaryData: {group: 'Actions', shortcut: 'mod+p'},},];export default function CommandPaletteRichItems() {const source = useMemo(() => createStaticSource(commands), []);return (<XDSCommandPaletteisOpenisInlineonOpenChange={() => {}}searchSource={source}renderItem={(item: RichCommand) => (<><XDSText type="body" style={{flex: 1}}>{item.label}</XDSText>{item.auxiliaryData?.shortcut && (<XDSKbd keys={item.auxiliaryData.shortcut} />)}</>)}/>);}
Showcase source
tsx'use client';import {useMemo} from 'react';import {XDSCommandPalette} from '@xds/core/CommandPalette';import {createStaticSource} from '@xds/core/Typeahead';// Remove isInline for production — command palettes should be modal.export default function CommandPaletteShowcase() {const source = useMemo(() =>createStaticSource([{id: 'home', label: 'Home'},{id: 'settings', label: 'Settings'},{id: 'profile', label: 'Profile'},{id: 'dashboard', label: 'Dashboard'},{id: 'help', label: 'Help'},]),[],);return (<XDSCommandPaletteisOpenisInlineonOpenChange={() => {}}searchSource={source}/>);}