# Connect your toolbar

Start with a Bold button, then understand commands, enabled state and interface updates.

The workspace accepts input. Add a Bold button: select text, click to change it through Core, then reflect its current formatting in the button.

Buttons, shortcuts and application code all call the same Editor commands rather than modifying document JSON themselves.

## 1. Run an action

```ts [Bold click handler]
editor.chain().focus().toggleBold().run()
```

`focus()` returns input focus, `toggleBold()` changes the current selection, and `run()` submits the chain. Use the existing selection rather than moving to the end of the document.

Use `editor.commands.toggleBold()` for an immediate single action; use `chain()` to combine focus, insertion or formatting.

## 2. Separate active and disabled state

A button answers two questions: is this text bold, and can Bold run now?

```ts [Ordinary Bold extension state]
const active = editor.isActive('bold')
const enabled = editor.isEditable && editor.can().toggleBold()
```

`isActive()` reads formatting; `can()` checks execution without changing content. Call `editor.setEditable(false)` to stop user editing input in the View; disabling controls alone does not stop keyboard editing. Programmatic commands still require application write-permission checks; see [commands and transactions](/en/concepts/commands).

Word formatting may inherit paragraph styles. Its assembly uses `readEffectiveDirectEmphasisState()` for effective bold state; the generic model uses `isActive('bold')`. Match button queries to the installed formatting extension.

## 3. Refresh controls after changes

Keep one Editor instance and expose only the booleans Vue needs. Subscribe to `transaction` and remove the same listener when exiting.

```ts [Subscribe and clean up]
editor.on('transaction', refreshToolbar)
// When the component exits:
editor.off('transaction', refreshToolbar)
```

Implement `refreshToolbar` to read a small set of formatting and history facts. Do not serialize the whole document with `getJSON()` on every selection movement. Saving status, file errors and page counts come from their respective workflows.

## Where to look in the complete project

`workspace.vue` owns controls and handlers, `session.ts` publishes their state, and `assembly/` supplies model-specific format queries. Inspect them individually in the [reference](/en/build/reference).

A command's boolean result means it handled the action, not that a file was saved. Next, use the same mechanism to [insert custom content](/en/build/extension). See [Editor API](/en/api/editor) for details.
