Commands
Command Composition
Compose command arrays locally instead of filtering registries by keys or tags.
Tulip no longer recommends registry-style command filtering for new code.
Instead of defining one large registry and then selecting commands with .pick(...), .omit(...), .tags(...), or .toArray(), define atomic command values and compose the array where the menu is rendered.
Recommended pattern
// app/admin/projects/_config/commands.tsx
export const projectCreateCommand = commandBuilder
.$type<null>()
.render(() => <CreateProjectCommand />);
export const projectUpdateStatusCommand = commandBuilder
.$type<{ id: string } | { id: string }[]>()
.transform(ensureArray)
.render(({ data }) => <UpdateProjectStatusCommand projects={data} />);
export const projectArchiveCommand = commandBuilder
.$type<{ id: string } | { id: string }[]>()
.transform(ensureArray)
.render(({ data }) => <ArchiveProjectCommand projects={data} />);
export const projectDeleteCommand = commandBuilder
.$type<{ id: string } | { id: string }[]>()
.transform(ensureArray)
.render(({ data }) => <DeleteProjectCommand projects={data} />);Usage:
<InlineCommandMenu data={null} commands={[projectCreateCommand]} />
<ResponsiveCommandMenu
data={project}
commands={[
projectUpdateStatusCommand,
projectArchiveCommand,
projectDeleteCommand,
]}
/>Why this is preferred
- the UI clearly shows which commands it renders
- command definitions stay reusable and typed
- no tags or selection query API to learn
- no vague group names like
singleCommands,bulkCommands, orglobalCommands - easier to debug because the final command list is explicit at the render site
When to extract a shared array
Default to local inline composition.
Only extract a shared array when all of these are true:
- the exact same combination is reused often
- the group has a clear domain meaning
- the extracted name is more helpful than the inline array
If that is not true, keep the array inline.
What to avoid
- registry objects that are later filtered by keys or tags
- exported array names that only describe mechanics (
single,bulk,global,table) - large shared command maps that hide what each page actually renders