Reference
API
Everything public, on one page. No engine type appears in any signature here · that is the contract, not a coincidence.
createEditor(options)
| Option | Type | |
|---|---|---|
| extensions | T | Required. The feature list · it decides the schema, the keymap and the type of `commands`. |
| content | DocNode | string | JSON or HTML. Anything the schema cannot hold is dropped on the way in. Parsing an HTML string needs a DOM · JSON and `fromMarkdown` output do not. |
| element | HTMLElement | Mount here immediately, instead of calling `mount` later. |
| editable | boolean | Defaults to true. |
| autofocus | boolean | 'start' | 'end' | Where to put the caret on mount. |
Editor
| Member | Returns | |
|---|---|---|
| commands | CommandsOf<T> & CoreCommands | Every command from every extension you passed in, typed. |
| can | CommandsOf<T> & CoreCommands | The same commands, returning what they would return and changing nothing. For disabling a button before it is pressed. |
| isActive(name, attrs?) | boolean | Is this mark on, or is the caret inside a node of this type? Marks are looked up first. |
| batch(run) | boolean | Run several commands as one undo step. Rolls back entirely if any returns false. |
| getJSON() | DocNode | The document as plain JSON. No engine types. |
| getHTML() | string | Serialised HTML, through the same security gate as rendering. |
| getText() | string | Block-separated plain text. |
| setContent(content) | void | Replace the document with JSON or an HTML string. |
| selection | Selection | Current from, to, anchor, head and empty. |
| editable / setEditable(v) | boolean / void | Read-only mode. |
| on(event, fn) | () => void | 'change' | 'focus' | 'blur' | 'selectionChange'. Returns its own unsubscribe. |
| extensionState(name) | S | undefined | What a stateful extension is currently holding. |
| mount(element) | void | Attach to the DOM. Or pass `element` to createEditor and skip it. |
| destroy() | void | Detach and clean up. |
| unsafe | { view, state, schema } | Raw engine. Unstable, outside semver · needing it is a gap in the API above. |
Core commands
Always present, whatever extensions you loaded. Every one returns a boolean.
| Command | Arguments | |
|---|---|---|
| select(range) | Range | Pos | Move the selection. |
| insert(content, at?) | DocNode | DocNode[] | string | Insert at a position, or at the caret. |
| replace(range, content) | Range, content | Swap a range for something else. |
| remove(range?) | Range? | Delete a range, or the selection. |
| moveBlock(from, to) | Pos, Pos | Move a whole block · what a drag does. |
| focus() | — | Put the caret back. |
A command never throws. Positions that are not finite integers inside the document return
false ·
NaN included, which slips past naive range checks because both
NaN < 0 and NaN > size are false.
Ctx · what a command receives
| doc / selection | The document and where the caret is. |
| hasMark(name, attrs?) | True if the mark covers the whole selection. |
| inNode(name, attrs?) | True if the selection sits inside such a node. |
| addMark / removeMark / toggleMark | Marks across a range. |
| setBlockType(name, attrs?) | Turn the block into another type. |
| wrapIn(name, attrs?) / lift() | Wrap the selection, or unwrap it. |
| insert / replace / delete / select | The same primitives the core commands expose. |
| mark() | A PosMarker. Map positions through changes made after this point. |
What an extension may declare
| commands | Plain functions of (ctx, …args) => boolean. Their types land on editor.commands and editor.can. |
| keys | A binding to a command name or a function · { 'Mod-Shift-S': 'toggleSpoiler' }. A binding that returns false lets the next one try. |
| inputRules | A RegExp on the text before the caret and a handler. One undo step each. |
| attributes | Attributes added to nodes and marks defined elsewhere, rendered and parsed. |
| handlePaste · handleDrop | Claim a paste or a drop before the editor parses it. Return true to keep it. |
| filterChange | Veto a change before it lands. Nothing is applied, recorded or redrawn when it returns false. |
| decorations | Draw over the document: inline attributes, node attributes, widgets. Never in the document. |
| state | init and apply, reduced on every transaction · read with editor.extensionState(name). |
| nodeViews | Render nodes defined elsewhere with your own DOM, keyed by node name. |
| onCreate · onChange · onDestroy | Lifecycle, each handed the editor. onCreate runs when the editor mounts. |
| priority | Load order. Higher loads first; a later binding for the same key wins. |
| nodes · marks | A node declares content, group, attrs, parseDOM, toDOM, nodeView, listItem, marks, code; a mark declares inclusive, excludes, parseDOM, toDOM. |
Types worth knowing
type Pos = number & { readonly __brand: unique symbol }
type Range = { from: Pos; to: Pos }
interface DocNode {
type: string
attrs?: Record<string, unknown>
content?: DocNode[]
text?: string
marks?: DocMark[]
} Pos is branded so a raw number cannot be passed by accident. Write one with
pos() rather than casting: a codebase where as Pos is ordinary is one
where the cast hiding a real mistake looks like all the others.
Writing a position down
import { pos, range } from '@matrajs/core'
pos(0) // number -> Pos
range(1, 6) // (number, number) -> Range Pos is branded so that arithmetic on one does not typecheck · these are how you write
a literal without a cast. Not for carrying a position across an await: that is ctx.mark().
Functions that need no editor
import { toMarkdown, fromMarkdown, tableOfContents, assignIds } from '@matrajs/core'
toMarkdown(doc) // DocNode -> string
fromMarkdown(source) // string -> DocNode
tableOfContents(doc) // DocNode -> TocEntry[]
assignIds(doc, options) // DocNode -> DocNode with stable block ids None of these touches the DOM, so all four run on a server.