Skip to content

ref(cmdk): Merge CMDKGroup and CMDKAction into single CMDKAction component#112563

Merged
JonasBa merged 1 commit intojb/cmdk/jsx-pocfrom
jb/jsx/onaction-callback
Apr 9, 2026
Merged

ref(cmdk): Merge CMDKGroup and CMDKAction into single CMDKAction component#112563
JonasBa merged 1 commit intojb/cmdk/jsx-pocfrom
jb/jsx/onaction-callback

Conversation

@JonasBa
Copy link
Copy Markdown
Member

@JonasBa JonasBa commented Apr 9, 2026

Changes

Merges CMDKGroup and CMDKAction into a single CMDKAction component. The distinction between the two was artificial — a node becomes a group simply by having children registered under it, which is already documented in the CMDKActionData type comment. Keeping them separate contradicted that stated design intent.

The merged CMDKAction covers all four cases:

Usage How
Navigation <CMDKAction display={...} to="/path/" />
Callback <CMDKAction display={...} onAction={fn} />
Group with children <CMDKAction display={...}><CMDKAction .../></CMDKAction>
Async resource group <CMDKAction display={...} resource={queryFn}>{data => ...}</CMDKAction>

CMDKActionDataTo.to is widened from string to LocationDescriptor to match CommandPaletteAsyncResult and the existing callsites.

…onent

A node becomes a group by virtue of having children registered under
it, so the Group/Action split was an artificial distinction. A single
CMDKAction now covers all cases: navigation (to), callbacks (onAction),
async resource groups (resource + render-prop children), and plain
parent groups (children only).

Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
@JonasBa JonasBa requested a review from a team as a code owner April 9, 2026 02:28
@github-actions github-actions bot added the Scope: Frontend Automatically applied to PRs that change frontend components label Apr 9, 2026
@JonasBa JonasBa merged commit 9a0a7c6 into jb/cmdk/jsx-poc Apr 9, 2026
54 of 58 checks passed
@JonasBa JonasBa deleted the jb/jsx/onaction-callback branch April 9, 2026 02:28
Comment on lines 88 to +94
const ref = CommandPaletteSlot.useSlotOutletRef();
const key = CMDKCollection.useRegisterNode({display, keywords, resource, ref});

const nodeData: CMDKActionData =
to === undefined
? onAction === undefined
? {display, keywords, ref, resource}
: {display, keywords, ref, onAction}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The CMDKAction component silently ignores the onAction prop if the to prop is also provided, due to a loss of type-level mutual exclusivity.
Severity: MEDIUM

Suggested Fix

Restore the type-level safety by using a discriminated union for the CMDKActionProps type. This will enforce that either to or onAction can be provided, but not both, preventing this issue at compile time. This was the behavior in the previous version of the component.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: static/app/components/commandPalette/ui/cmdk.tsx#L88-L94

Potential issue: The `CMDKAction` component's props interface was changed from a
discriminated union to a single interface with optional `to` and `onAction` props. This
removes the compile-time guarantee that only one can be provided. The component's
implementation prioritizes the `to` prop for navigation. If a developer provides both
`to` and `onAction` on the same component, the `onAction` callback will be silently
ignored, and only the navigation will occur. This is a type safety regression that could
lead to unexpected behavior where a developer's intended action does not execute.

Did we get this right? 👍 / 👎 to inform future reviews.

Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit c85059a. Configure here.


/**
* Registers a leaf action node in the collection.
*/
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaf actions unnecessarily subscribe to query state

Medium Severity

The merged CMDKAction unconditionally calls useCommandPaletteState() and useQuery() for every instance, including leaf actions that have no resource and no children. Previously, leaf CMDKAction was lightweight (register + return null). Now every leaf subscribes to the query context, causing all leaf actions to re-render on every keystroke in the palette. With dozens of static leaves plus dynamic ones (projects, settings), this is a meaningful regression in a typing-heavy interaction.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c85059a. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Frontend Automatically applied to PRs that change frontend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant