Features Apograph CMS on GitHub

The rich-text editor

Rich text plugin @apograph/wysiwyg-admin

What the editor can do, and the structural checks it runs while you write rather than after you save.

Documents 0.5.2 Updated Edit this page Report a problem

On this page

A richtext field shows its content as it reads. Pressing it expands a TipTap editor into the record’s work area, with the formatting toolbar.

What it can do

GroupControls
TextStyle and size, bold, italic, underline, strikethrough, inline code
ColourText colour and highlight
LayoutAlignment, bullet and ordered lists, blockquote, horizontal rule
BlocksCallouts, tables, column layouts, code blocks
LinksInsert and edit, with the link text
MediaEmbedded images and video, resizable

Media comes from the media library, through an extension point the media plugin fills — so the editor itself knows nothing about where assets live.

What it stores

The document — the node tree — not an HTML string. That is what makes a body’s heading order, its tables’ header cells and the language of a quoted passage into things the system can check. See rich text for the stored shape.

A body written before the editor stored documents is still an HTML string in the column. Opening it seeds the editor, which parses it through its own schema, and the first save commits a document — so content upgrades as it is edited rather than in one migration that has to guess what an unknown tag meant.

It checks as you write

The editor shows the same structural findings the server enforces, while you are still in a position to fix them:

FindingBlocks a save
A heading that skips a levelYes
A heading above the body’s own top levelYes
An empty headingYes
A table with no header cells and no captionYes
A link with no textYes
A lang marker nothing can parseYes
Link text that says nothing about where it goesNo — advice

Each one names the accessibility criterion it comes from.

The editor deliberately shows the whole list, warnings included, while the server only refuses the errors. A rule nobody sees until a save fails does not help anyone produce better content — which is the difference between a tool that permits accessible output and one that helps you write it.

Language of a passage

Selecting text and marking its language records a lang on that run, which becomes a lang attribute when rendered. That is how a quoted sentence in another language gets announced correctly by a screen reader.

For a field whose whole value is in another language, the content type sets it instead — see the lang option on fields.

Turning it off for a field

Some bodies are not authored prose — a hand-maintained snippet, an email template, anything you edit as markup on purpose, which a rich-text editor would reformat the moment it opened.

body: field.richtext(),                                  // the editor
raw:  field.richtext({ admin: { widget: 'textarea' } })  // a plain textarea

widget: 'wysiwyg' is accepted too, so a schema can state the intent rather than rely on the default.

To also stop the server enforcing document structure on such a field:

raw: field.richtext({
    admin: { widget: 'textarea' },
    validation: { structure: 'off' }
})

Rendering it

The editor stores a tree, so rendering is your front end’s job — walk the nodes and emit what your framework wants. A documentToHtml helper is available if you want HTML directly.

No collaborative editing

One person edits a record at a time. There is no real-time collaboration, no presence indicators, no operational transform and no websocket layer — two people editing the same entry will overwrite each other, last save winning.