Skip to main content
useSuperDocCommand(id) subscribes one button to one command. The component re-renders when that command flips active or disabled, never on every editor change. ui.commands.get(id)?.execute(payload?) runs the command.

A single button

A row of buttons

Build a static config and map. Each <ToolbarButton> subscribes to its own command, so unrelated state changes don’t re-render the row.
See the configurable toolbar example for a runnable vanilla version: a config-driven button row that subscribes per-id and reads disabled / active straight from the controller.

Commands with payloads

Some commands take a value. Pass it to execute().

What the hook returns

useSuperDocCommand returns a fallback { active: false, disabled: true, source: 'built-in' } while the editor is initializing, so your buttons render disabled with no flicker.

Built-in command ids

Common ids you’ll wire to buttons: PublicToolbarItemId in superdoc/ui is the source of truth. Anything you can pass to createHeadlessToolbar({ commands }) works as a useSuperDocCommand id.

Aggregate snapshots

Need every command in one render pass (e.g. you generate the toolbar from the active context)? Subscribe to the whole toolbar slice.
Prefer useSuperDocCommand per button when you can. useSuperDocToolbar re-renders on any command change.

Trade-offs

  • The hook subscribes per-id. Reusing a button component with different ids is fine: the subscription resets when id changes.
  • Built-in command state is derived from the active editor. If your provider sits above multiple editors, the ids you pass are scoped to whichever editor reported ready last.
  • Custom commands you registered with ui.commands.register work with the same hook.