Getting started
Styling
Matra ships no appearance at all. Mount an editor and you get a
contenteditable element holding plain, unstyled HTML — a heading looks like a heading
only because your stylesheet says so. That is what headless means, and it is the reason the same
package makes a comment box and a document editor.
There are three separate things to know, and they are easy to conflate.
1 · The document is yours to style
The editor renders ordinary tags — <p>, <h2>,
<ul>, <blockquote>, <table>. Style
them the way you style any prose on your site. Scope it to the editor and you are done:
.matra-editor { outline: none; white-space: pre-wrap; }
.matra-editor h2 { font-size: 1.5rem; margin: 1.5rem 0 .5rem; }
.matra-editor p { margin: 0 0 .75rem; line-height: 1.6; }
.matra-editor blockquote { border-left: 2px solid #ccc; padding-left: 1rem; }
.matra-editor pre { background: #f4f4f4; padding: 1rem; white-space: pre-wrap; } white-space: pre-wrap is not optional. HTML collapses runs of whitespace and drops
a trailing one, so without it pressing space at the end of a line does nothing visible until
the next character arrives — which reads as a dropped keystroke.
It is set twice on purpose. A pre carries the browser's own
white-space: pre, which beats the value inherited from the editor around it,
so a code block that does not restate it grows a horizontal scrollbar inside a document
that is already scrolling. overflow-x: auto is the other way to answer that, and
it is the worse one.
2 · Some extensions bring a stylesheet
An extension that renders something the document does not contain — a checkbox, a drag handle, a remote caret — cannot leave its appearance entirely to you, because there is no tag for you to target. Each of those exports the CSS it needs as a string. Paste it, inject it, or copy the rules out and rewrite them; nothing is minified and nothing is obfuscated.
| Export | From | What it draws |
|---|---|---|
placeholderCSS | @matrajs/core | The hint in an empty block |
taskListCSS | @matrajs/core | Checkboxes, and the line through a done item |
suggestionCSS | @matrajs/core | The highlight on a live query, and mention chips |
dragHandleCSS | @matrajs/core | The handle that appears beside a block |
commentCSS | @matrajs/core | The tint under a commented range |
remoteCursorCSS | @matrajs/collab | Other people’s carets and their labels |
versionDiffCSS | @matrajs/versions | What a preview marks as added or changed |
import { placeholderCSS, taskListCSS, suggestionCSS } from '@matrajs/core'
const sheet = new CSSStyleSheet()
sheet.replaceSync(placeholderCSS + taskListCSS + suggestionCSS)
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet] Or, if you would rather own them, open the file and copy the rules into your own stylesheet. They are a starting point, not a dependency — every one of them is a handful of lines and none of them is imported by the extension itself.
3 · A slash menu is state, not a menu
This is the one that catches people. suggestion() does not draw a menu. It watches
for the trigger character, tracks the query as you type, exposes the range it covers, and gives
you acceptSuggestion and cancelSuggestion. What it hands you is a
piece of state:
import { activeSuggestion } from '@matrajs/core'
const active = activeSuggestion(editor, 'slash')
// null when nothing is open, or:
// { query: 'head', range: { from: 12, to: 17 }, from: 12 } The list, its position, its keyboard behaviour and its appearance are yours. That is deliberate: a menu is the most opinionated thing in an editor and the thing every product wants to look like its own. The menu on this site is about three hundred lines of ordinary DOM code with no framework, and it is in the repository — copy it and change it rather than starting from nothing.
The same is true of a toolbar, a bubble menu and a comment sidebar. The editor gives you the state and the commands; the interface is the part you were going to design anyway.
What this costs you
An afternoon at the start, and no fighting later. The alternative — an editor that arrives with a theme — is a week saved on day one and then a month spent overriding selectors when the design changes. If you want a running start, every editor on the home page and the extensions page is a real one, and the CSS behind them is in the same repository.