Commands

PreviousNext

While editing richtext content, your users will be doing things like inserting text, deleting text, splitting paragraphs, and adding formatting. Under the cover these edits are expressed as operations. At the public API level, write them with editor.update(...) and transaction methods.

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

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.