Skip to content

Commit 4406dc2

Browse files
JonasBaclaude
andcommitted
docs(cmdk): Update story to JSX-powered command palette API
Replace the useCommandPaletteActions hook example with the new JSX component API using CMDKAction, CMDKGroup, and CommandPaletteProvider. Also adds a section documenting the async resource pattern. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 0158ce5 commit 4406dc2

File tree

1 file changed

+93
-36
lines changed

1 file changed

+93
-36
lines changed
Lines changed: 93 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
2-
title: useCommandPaletteActions
3-
description: Registers actions with the command palette
4-
source: 'sentry/components/commandPalette/useCommandPaletteActions'
2+
title: CommandPalette JSX API
3+
description: Registers actions with the command palette using JSX components
4+
source: 'sentry/components/commandPalette/ui/cmdk'
55
---
66

77
import {Fragment} from 'react';
@@ -12,21 +12,20 @@ import {Flex, Stack} from '@sentry/scraps/layout';
1212
import {addSuccessMessage} from 'sentry/actionCreators/indicator';
1313
import {toggleCommandPalette} from 'sentry/actionCreators/modal';
1414

15-
import {CommandPaletteProvider} from 'sentry/components/commandPalette/context';
16-
1715
import * as Storybook from 'sentry/stories';
1816

19-
import {CommandPaletteDemo, RegisterActions} from './__stories__/components';
17+
import {CommandPaletteDemo} from './__stories__/components';
2018

2119
## Basic Usage
2220

23-
Use `useCommandPaletteActions(actions)` inside your page or feature component to register contextual actions with the global command palette. Actions are registered on mount and automatically unregistered on unmount, so they only appear in the palette while your component is rendered. This is ideal for page‑specific shortcuts.
21+
Use `CMDKAction` and `CMDKGroup` JSX components inside your page or feature component to register contextual actions with the global command palette. Actions are registered on mount and automatically unregistered on unmount, so they only appear in the palette while your component is rendered. This is ideal for page‑specific shortcuts.
2422

25-
There are a few different types of actions you can register:
23+
Wrap your tree in `CommandPaletteProvider` and place the `CommandPalette` UI component wherever you want the dialog to render. Then declare actions anywhere inside the provider:
2624

27-
- **Navigation actions**: Provide a `to` destination to navigate to when selected.
25+
- **Navigation actions**: Provide a `to` prop to navigate when selected.
2826
- **Callback actions**: Provide an `onAction` handler to execute when selected.
29-
- **Nested actions**: Provide an `actions: CommandPaletteAction[]` array on a parent item to show a second level. Selecting the parent reveals its children.
27+
- **Grouped actions**: Wrap `CMDKAction` children inside a `CMDKGroup` to show a second level. Selecting the parent reveals its children.
28+
- **Async actions**: Provide a `resource` prop to a `CMDKGroup` and use the render-prop children signature to generate actions from fetched data.
3029

3130
<Storybook.Demo>
3231
<Flex width="100%">
@@ -35,34 +34,92 @@ There are a few different types of actions you can register:
3534
</Storybook.Demo>
3635

3736
```tsx
38-
import {useCommandPaletteActions} from 'sentry/components/commandPalette/useCommandPaletteActions';
37+
import {useCallback} from 'react';
38+
39+
import {addSuccessMessage} from 'sentry/actionCreators/indicator';
40+
import {
41+
CMDKAction,
42+
CMDKGroup,
43+
CommandPaletteProvider,
44+
} from 'sentry/components/commandPalette/ui/cmdk';
45+
import type {CMDKActionData} from 'sentry/components/commandPalette/ui/cmdk';
46+
import type {CollectionTreeNode} from 'sentry/components/commandPalette/ui/collection';
47+
import {CommandPalette} from 'sentry/components/commandPalette/ui/commandPalette';
48+
import {normalizeUrl} from 'sentry/utils/url/normalizeUrl';
49+
import {useNavigate} from 'sentry/utils/useNavigate';
3950

4051
function YourComponent() {
41-
useCommandPaletteActions([
42-
{
43-
display: {label: 'Go to Input story'},
44-
to: '/stories/core/input/',
45-
groupingKey: 'navigate',
46-
},
47-
{
48-
display: {label: 'Execute an action'},
49-
groupingKey: 'help',
50-
onAction: () => {
51-
addSuccessMessage('Action executed');
52-
},
53-
},
54-
{
55-
groupingKey: 'add',
56-
display: {label: 'Parent action'},
57-
actions: [
58-
{
59-
display: {label: 'Child action'},
60-
onAction: () => {
61-
addSuccessMessage('Child action executed');
62-
},
63-
},
64-
],
52+
const navigate = useNavigate();
53+
54+
const handleAction = useCallback(
55+
(action: CollectionTreeNode<CMDKActionData>) => {
56+
if ('to' in action) {
57+
navigate(normalizeUrl(String(action.to)));
58+
} else if ('onAction' in action) {
59+
action.onAction();
60+
}
6561
},
66-
]);
62+
[navigate]
63+
);
64+
65+
return (
66+
<CommandPaletteProvider>
67+
{/* Navigation action */}
68+
<CMDKAction display={{label: 'Go to Flex story'}} to="/stories/layout/flex/" />
69+
70+
{/* Callback action */}
71+
<CMDKAction
72+
display={{label: 'Execute an action'}}
73+
onAction={() => addSuccessMessage('Action executed')}
74+
/>
75+
76+
{/* Grouped actions */}
77+
<CMDKGroup display={{label: 'Parent action'}}>
78+
<CMDKAction
79+
display={{label: 'Child action'}}
80+
onAction={() => addSuccessMessage('Child action executed')}
81+
/>
82+
</CMDKGroup>
83+
84+
{/* The command palette UI — also accepts inline actions via children */}
85+
<CommandPalette onAction={handleAction}>
86+
<CMDKGroup display={{label: 'Issues List'}}>
87+
<CMDKAction
88+
display={{label: 'Select all'}}
89+
onAction={() => addSuccessMessage('Select all')}
90+
/>
91+
<CMDKAction
92+
display={{label: 'Deselect all'}}
93+
onAction={() => addSuccessMessage('Deselect all')}
94+
/>
95+
</CMDKGroup>
96+
</CommandPalette>
97+
</CommandPaletteProvider>
98+
);
6799
}
68100
```
101+
102+
## Async / Resource Actions
103+
104+
`CMDKGroup` accepts a `resource` prop — a function that takes the current search query and returns a TanStack Query options object. The `children` prop becomes a render function that receives the fetched results:
105+
106+
```tsx
107+
import type {CommandPaletteAsyncResult} from 'sentry/components/commandPalette/types';
108+
109+
<CMDKGroup
110+
display={{label: 'Projects'}}
111+
resource={query => ({
112+
queryKey: ['/projects/', {query}],
113+
queryFn: () => fetchProjects(query),
114+
// transform response into CommandPaletteAsyncResult[]
115+
select: (data): CommandPaletteAsyncResult[] =>
116+
data.map(p => ({display: {label: p.name}, to: `/projects/${p.slug}/`})),
117+
})}
118+
>
119+
{(results: CommandPaletteAsyncResult[]) =>
120+
results.map(r => (
121+
<CMDKAction key={'label' in r.display ? r.display.label : ''} {...r} />
122+
))
123+
}
124+
</CMDKGroup>;
125+
```

0 commit comments

Comments
 (0)