Commands

PreviousNext

Group user and product intent into reusable functions that run Slate transactions.

Commands are high-level actions that represent user or product intent. In Slate, command helpers are ordinary functions that run related transaction writes inside editor.update(...).

Command Shape

For example, here are some of the built-in commands:

editor.update((tx) => {
  tx.text.insert("A new string of text to be inserted.");
});
 
editor.update((tx) => {
  tx.text.delete({ reverse: true, unit: "word" });
});
 
editor.update((tx) => {
  tx.nodes.split({ always: true });
});
editor.update((tx) => {
  tx.text.insert("A new string of text to be inserted.");
});
 
editor.update((tx) => {
  tx.text.delete({ reverse: true, unit: "word" });
});
 
editor.update((tx) => {
  tx.nodes.split({ always: true });
});

Define custom commands for your product domain, such as formatQuote, insertImage, or toggleBold.

Commands usually act on the current selection. Pass an explicit at location only when the command is intentionally targeting another part of the document.

Slate turns transaction writes into operations during the update. That is the boundary used by history, collaboration, and tests.

Custom Commands

When defining custom commands, pass the editor into a function and keep the writes grouped:

import type { Editor } from "@platejs/slate";
 
function insertParagraph(editor: Editor) {
  editor.update((tx) => {
    tx.nodes.insert({ type: "paragraph", children: [{ text: "" }] });
  });
}
import type { Editor } from "@platejs/slate";
 
function insertParagraph(editor: Editor) {
  editor.update((tx) => {
    tx.nodes.insert({ type: "paragraph", children: [{ text: "" }] });
  });
}

When writing your own commands, compose transaction methods inside one update:

import { ElementApi, TextApi } from "@platejs/slate";
 
editor.update((tx) => {
  tx.nodes.set(
    { bold: true },
    {
      at: range,
      match: (node) => TextApi.isText(node),
      split: true,
    }
  );
 
  tx.nodes.wrap(
    { type: "quote", children: [] },
    {
      at: point,
      match: (node) => ElementApi.isElement(node) && tx.schema.isBlock(node),
      mode: "lowest",
    }
  );
 
  tx.text.insert("A new string of text.", { at: path });
});
import { ElementApi, TextApi } from "@platejs/slate";
 
editor.update((tx) => {
  tx.nodes.set(
    { bold: true },
    {
      at: range,
      match: (node) => TextApi.isText(node),
      split: true,
    }
  );
 
  tx.nodes.wrap(
    { type: "quote", children: [] },
    {
      at: point,
      match: (node) => ElementApi.isElement(node) && tx.schema.isBlock(node),
      mode: "lowest",
    }
  );
 
  tx.text.insert("A new string of text.", { at: path });
});

Transaction methods are designed to be composed together. Keep related writes in the same editor.update(...) so selection, operations, history, and React rendering share one commit.