> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lumen.bjanczak.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Lumen Editor Events: change, error, autosave & More

> All Lumen Editor events, their payload types, and exactly when they fire — including change, error, autosave, view:toggle, and selectionchange.

Lumen Editor exposes a built-in event system that lets you react to content changes, cursor movement, view switches, auto-save cycles, and errors without polling or wrapping the DOM. Every event is subscribed through `editor.on()` and unsubscribed through `editor.off()`.

## Subscribing to Events

Use `editor.on()` to register a handler and `editor.off()` to remove it. Always hold a named reference to the callback function if you intend to unsubscribe later.

```js theme={null}
// Subscribe
function handleChange(html) {
  console.log('New content:', html);
}
editor.on('change', handleChange);

// Unsubscribe
editor.off('change', handleChange);
```

<Tip>
  Always subscribe to the `error` event during development and in production. It is the only way to learn about silent failures such as image upload rejections and sanitizer errors — the editor does not throw exceptions for these conditions.
</Tip>

***

## `change`

Fires on every content change in the editor — keystrokes, pastes, formatting commands, `setHTML()` calls, and undo/redo operations all trigger this event.

<ResponseField name="html" type="string">
  The full editor content as a sanitized HTML string at the moment of the change.
</ResponseField>

```js theme={null}
editor.on('change', (html) => {
  // Persist to your backend or state store
  debouncedSave(html);
});
```

***

## `selectionchange`

Fires whenever the cursor position or text selection changes inside the editor. No payload is delivered — query `editor.getHTML()` or inspect `window.getSelection()` inside the handler if you need context about the current selection.

```js theme={null}
editor.on('selectionchange', () => {
  // Update a custom formatting toolbar to reflect the active styles
  updateActiveFormats();
});
```

***

## `history:change`

Fires when the undo/redo stack changes — both when a new snapshot is pushed and when the user navigates the history. Use this to enable or disable custom undo/redo UI controls.

```js theme={null}
editor.on('history:change', () => {
  // Re-evaluate which history buttons should be enabled
  syncHistoryButtons();
});
```

***

## `view:toggle`

Fires after the editor transitions between WYSIWYG mode and raw HTML editing mode, either programmatically via `toggleHtmlView()` or through the built-in toolbar button.

<ResponseField name="isHtml" type="boolean">
  `true` when the editor has just entered raw HTML mode; `false` when it has returned to WYSIWYG mode.
</ResponseField>

```js theme={null}
editor.on('view:toggle', (isHtml) => {
  const label = isHtml ? 'Switch to Visual' : 'Switch to HTML';
  document.querySelector('#toggle-btn').textContent = label;
});
```

***

## `autosave`

Fires after the editor successfully writes content to `localStorage`. This event only fires when the `autoSave` option is configured. No payload is delivered.

```js theme={null}
editor.on('autosave', () => {
  // Show a brief "Saved" indicator in your UI
  showSavedBadge();
});
```

<Note>
  The `autosave` event fires after a successful write. It does **not** fire if `localStorage` is unavailable or throws (e.g. in private browsing with storage blocked). Subscribe to `error` to catch storage failures.
</Note>

***

## `error`

Fires when a recoverable error occurs inside the editor. The editor does not throw exceptions for these conditions — it emits them as events so you can decide how to surface them to the user.

<ResponseField name="code" type="string">
  A machine-readable error code string. See the [Error codes](#error-codes) table below.
</ResponseField>

<ResponseField name="message" type="string">
  A human-readable description of what went wrong.
</ResponseField>

```js theme={null}
editor.on('error', ({ code, message }) => {
  console.error(`Lumen Editor error [${code}]: ${message}`);

  if (code === 'UPLOAD_TOO_LARGE') {
    showToast('Image is too large. Maximum size is 5 MB.');
  } else if (code === 'UPLOAD_INVALID_TYPE') {
    showToast('Only PNG, JPEG, GIF, and WebP images are supported.');
  } else {
    showToast('An error occurred. Please try again.');
  }
});
```

***

## Error Codes

The following codes appear in the `error` event's `code` field:

| Code                   | Trigger                                                                                       |
| ---------------------- | --------------------------------------------------------------------------------------------- |
| `UPLOAD_TOO_LARGE`     | The selected image file exceeds the `maxImageSize` limit (default 5 MB).                      |
| `UPLOAD_INVALID_TYPE`  | The file's MIME type is not in the `allowedImageTypes` list.                                  |
| `UPLOAD_INVALID_MAGIC` | The file's magic bytes do not match its declared MIME type — likely a spoofed file extension. |
| `UPLOAD_FAILED`        | The `uploadImage` callback threw an exception or returned a falsy value.                      |
