The editor you are
already using.

Every word on this page is a Matra document. Select this sentence and press Mod-B. Start a new line and press / for the block menu. Type "quotes" and watch them curl. Nothing here is a screenshot and nothing is a video. It is the product, at the size the table further down claims.

npm i @matrajs/core

What you get

Not a demo.
The actual editor.

This block has the whole extension set on. Press / on an empty line for the block menu, or start typing with #, - or [] and skip it. Mod-B, Mod-I, Mod-Z all work. Break it however you like; a reload puts it back.

Try it properly

Undo groups by what you did rather than by keystroke, so one Mod-Z takes back a whole word instead of one letter. Typing "smart quotes" curls them, and two hyphens -- become an em dash.

  • Tick this · a real node, not a glyph

  • Add a line and watch the list continue

A quote, because a quote is a block and blocks are what this is made of.

Empty line, then / — the menu only lists what this editor can do.

Headless, demonstrated

One package,
five different editors.

None of these is a theme or a preset. Each is createEditor with a different array of extensions and different CSS around it. All five are live, and all five share one 31.1 kB download.

01 · Block editor

The Notion shape.

Every block type, every mark, the slash menu and the markdown shortcuts. Press / on the empty line, or start one with #, -, 1. or [].

starterKit · taskList · typography · suggestion · placeholder

block-editor.md

02 · Comment box

Three marks, deliberately.

Bold, italic, code, and nothing else. A comment box that can make headings is a bug report waiting to happen · constraining an editor is the same work as extending one.

document · paragraph · text · bold · italic · code

comment.txt
Nahim commented
0 characters

03 · Document

A toolbar over a page.

Headings, quotes, alignment, tables, undo. Every button is a command call, and the command types come from the array of extensions rather than from a declaration.

starterKit · tableKit · textAlign · typography

quarterly-note.doc

04 · Markdown

Out, without a DOM.

The panel beside this is toMarkdown running on every keystroke. It never touches the DOM, so the same call runs on a server with no jsdom in sight.

starterKit · taskList · toMarkdown

notes.md

05 · Chat composer

One block, and a send key.

No headings, no lists, no way to paste a document into a message box. Enter sends, Shift-Enter breaks the line.

document · paragraph · text · bold · italic · hardBreak

messages
Did the drag handle land?
It did · and it is free, which Tiptap's is not.

Measured, not claimed

Faster where it is felt.

Four editors, one browser, one run. Shorter is faster.

measuring…per keystroke, 2,000 paragraphs
·to read that document in
·to write it back out

running in your browser…

Read a document in 2,000 paragraphs 3.7× ahead
Matra
2.2 ms
Tiptap
8.1 ms
Lexical
35.8 ms
Slate
not measured
Write it back out as HTML 2,000 paragraphs 5.7× ahead
Matra
0.300 ms
Tiptap
1.7 ms
Lexical
5.3 ms
Slate
not measured
One keystroke 2,000 paragraphs 1.1× ahead
Matra
0.480 ms
Tiptap
0.622 ms
Lexical
0.547 ms
Slate
not measured
One keystroke 200 paragraphs 1.4× ahead
Matra
0.073 ms
Tiptap
0.158 ms
Lexical
0.102 ms
Slate
not measured
Put an editor on screen 200 paragraphs 1.9× ahead
Matra
1.2 ms
Tiptap
4.6 ms
Lexical
2.3 ms
Slate
5.0 ms
Put an editor on screen 2,000 paragraphs 1.5× ahead
Matra
14.6 ms
Tiptap
34.1 ms
Lexical
21.6 ms
Slate
50.2 ms

Slate's keystroke is blank because the harness would not print it: nothing had reached the screen when the timer stopped. Method, caveats and how to run it yourself →

Extensions

A small core.
Everything else hangs off it.

Nodes, marks and behaviour are all the same shape: a plain object with a name. 7 of these 10 groups are in the core and MIT, including four that are paid features elsewhere.

Text
@matrajs/core
  • bold
  • italic
  • strike
  • code
  • underline
  • highlight
  • link
  • subscript
Blocks
@matrajs/core
  • heading
  • blockquote
  • codeBlock
  • lists
  • taskList
  • image
  • rule
Structure
@matrajs/core
  • table
  • tableOfContents
  • uniqueId
  • dragHandle
  • comments
Writing
@matrajs/core
  • placeholder
  • characterCount
  • textAlign
  • typography
  • markdown
  • search
  • autosave
Templates
@matrajs/core
  • locked
  • field
  • snippets
Layout
@matrajs/core
  • columns
  • pageBreak
  • embed
  • footnotes
  • math
Menus
@matrajs/core
  • suggestion
  • mention
  • bubbleMenu
  • ghostText
  • dictation
AI
@matrajs/ai
  • streaming edits
  • position markers
Collaborate
@matrajs/collab
  • authority
  • rebasing
  • remote cursors
History
@matrajs/versions
  • snapshots
  • block diff
  • word diff
  • restore

Three lines

The whole API,
more or less.

Extensions are plain objects. Command types are inferred from the array you pass in, so editor.commands knows what exists without a declaration merge.

Your first editor
editor.ts
import { createEditor, starterKit } from '@matrajs/core'

const editor = createEditor({
  extensions: starterKit,
  content: '<p>Hello.</p>',
})

editor.mount(document.querySelector('#editor'))
editor.commands.toggleBold() // typed, inferred

Against the alternatives

An honest table.

What you ship, and what you get for it.

Downloaded on every visit gzipped 4× smaller
Matra
31.1 kB core and starter kit
Tiptap
119.8 kB with ProseMirror
Lexical
94.0 kB with rich-text
Slate
63.0 kB 29.0 kB without React
MatraTiptapLexicalSlate
Runtime dependencies none 51 packages 9 packages React
Engine types in your code none ProseMirror Lexical Slate
Command types inferred augmentation manual manual
Async position safety built in manual manual manual
Markdown without a DOM yes no no no
Table of contents free paid build it build it
Unique block ids free paid build it build it
Drag handle free paid build it build it
Comments free paid build it build it
Runtime licence check never none · ·

Where they win: ProseMirror's ecosystem is a decade deep and Tiptap inherits all of it. If you need a mature extension for something exotic today, they have it and this does not.

The core is MIT,
and stays that way.

AI and collaboration are what a subscription is for. Everything else, permanently, is not.

npm i @matrajs/core · 31.1 kB · zero dependencies