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.8 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 the whole editor is still 31 kB.

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.

In the core

MIT, and permanently

Text
  • bold
  • italic
  • strike
  • code
  • underline
  • highlight
  • link
  • subscript
Blocks
  • heading
  • blockquote
  • codeBlock
  • lists
  • taskList
  • image
  • rule
Structure
  • table
  • tableOfContents
  • uniqueId
  • dragHandle
  • comments
Writing
  • placeholder
  • characterCount
  • textAlign
  • typography
  • markdown
  • search
  • autosave
Templates
  • locked
  • field
  • snippets
Layout
  • columns
  • pageBreak
  • embed
  • footnotes
  • math
Menus
  • suggestion
  • mention
  • bubbleMenu
  • ghostText
  • dictation

Paid packages

free to try, licensed in production

AI
ai
  • streaming edits
  • position markers
Collaborate
collab
  • authority
  • rebasing
  • remote cursors
History
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.8 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
Packages installed 2 50 34 12
Third-party code none 22 packages 10 packages 8 packages
Engine types in your code none ProseMirror Lexical Slate
Command types inferred augmentation manual manual
Async position safety built in manual manual manual
Comments free paid build it build it
Svelte and Solid bindings first-class community community community
Runtime licence check never none · ·

The full comparison, including what Tiptap does better · package counts measured on 2026-09-08 by resolving each install with npm · Tiptap 3.31.3, Lexical 0.50.0, Slate 0.126.2. 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.8 kB · zero dependencies