Events – inksane
inksane
Introduction

Events

React to document changes, selection changes, and the editor lifecycle.

The editor is an event emitter. Subscribe with editor.on(name, listener) and unsubscribe with editor.off(name, listener). Every listener receives the event payload, which always contains the editor.

const handleUpdate = ({ editor, transaction }) => {
  console.log(editor.getMarkdown(), transaction);
};

editor.on("update", handleUpdate);

editor.off("update", handleUpdate);

once(name, listener) subscribes for a single call. removeEventListeners(name) drops every listener for one event, and removeListeners() drops all of them.

Events

EventPayloadWhen it fires
beforeCreate{ editor }In the constructor, before the editor state exists.
create{ editor }After the editor is created, and after mounting when element was passed.
mount{ editor }After the CodeMirror view is created in mount().
unmount{ editor }Before the view is destroyed in destroy().
destroy{ editor }After destroy() ran.
update{ editor, transaction }After a transaction changed the document.
selectionUpdate{ editor, selection }After a transaction changed the selection.
focus{ editor }After the editor gains DOM focus.
blur{ editor }After the editor loses DOM focus.
beforeTransaction{ editor, transaction }Before the mounted view applies a dispatched transaction batch.
transaction{ editor, transaction }After the mounted view applies a transaction batch, once per transaction.

Transactions

beforeTransaction and transaction fire for every transaction dispatched to the mounted view, including selection changes, effects, and transactions with no document changes. Both receive the same CodeMirror Transaction object. Content changes made before mounting do not emit these events.

For a batch, all beforeTransaction listeners run before the batch is applied and see the old editor state. Then transaction fires for each transaction in order, with the editor in the final batch state. Read transaction.startState and transaction.state for each transaction’s own states. These events observe transactions. They do not cancel or replace them.

editor.on("beforeTransaction", ({ transaction }) => {
  console.log("before", transaction.startState.doc.toString());
});

editor.on("transaction", ({ transaction }) => {
  console.log("after", transaction.state.doc.toString());
});

Document changes

update fires for typing, pasting, and every command that changes the document. The payload includes the CodeMirror transaction, which has the changes and the new state.

editor.on("update", ({ editor }) => {
  save(editor.getMarkdown());
});

Selection changes

selectionUpdate fires when the cursor or the selected range changes, including when a command moves the selection.

editor.on("selectionUpdate", ({ selection }) => {
  toolbar.setActive(selection.main.from !== selection.main.to);
});

In React, useInksaneSelection() wraps this event. See the React guide.

Focus changes

focus and blur fire when the editor’s focus state changes. The payload contains only editor, and editor.focused already reflects the new state when the listener runs. Focusing an editor that already has focus does not emit another event. These events also work in read-only mode.

editor.on("focus", ({ editor }) => {
  toolbar.setVisible(editor.focused);
});

editor.on("blur", ({ editor }) => {
  save(editor.getMarkdown());
});

Lifecycle

create runs once per editor. mount runs when the editor attaches to an element, which happens right after creation when you pass element, or later when you call mount() yourself. destroy runs when you tear the editor down.

An editor created with element emits mount while the constructor runs, before any listener can subscribe. Create the editor without an element when you need to observe the mount:

const editor = new Editor({});

editor.on("mount", ({ editor }) => console.log("mounted", editor.isMounted));
editor.on("destroy", () => console.log("gone"));

editor.mount(document.getElementById("editor")); // logs "mounted true"

For an editor that may already be mounted, check editor.isMounted instead.

Events on extensions

Extensions can declare handlers named after these events. The extension manager registers them before beforeCreate, including handlers from child extensions. Higher-priority extensions run first. Each handler receives { editor } followed by the event payload. All listeners are removed when the editor is destroyed, after the destroy handlers run.