Components · Rich text editor

Editor content

The .prose render surface — the typography the editor shares between reading and writing, so a doc looks identical whether you're editing it or just viewing it. Headings are set in the display serif; body copy carries bold, italic and accent links; lists, an accent-ruled blockquote, and both inline code and a fenced block sit on layered surfaces. Shown here in its read-only form — editable={false} hides the toolbar and drops the caret, leaving a clean prose render.

Prose surface · editable={false} · shared read / write typography

Transport run — Athens → Atlanta, Saturday

The Saturday convoy leaves the Athens staging lot at 6:00 AM sharp. Confirm your leg on the volunteer roster before Friday noon so we can size crates and line up hand-offs at each checkpoint.

Every driver is responsible for the animals in their vehicle for the full leg:

  • Bring a printed health certificate for each beagle you're carrying
  • Line crates with puppy pads — the middle leg runs about 3.5 hours
  • Text the group the moment you clear a checkpoint

Never leave a dog unattended in a parked vehicle, not even for five minutes. If a hand-off is running late, wait with the animals and call the leg captain.

— Transport safety protocol, rev. 4

Log every transfer against the run ID ATL-0712 in the shared manifest — the dispatcher reconciles head-count at each hop:

# manifest — one line per leg
run:    ATL-0712
legs:
  - athens   → commerce   (M. Reyes)
  - commerce → atlanta    (W. Chen)
crates: 14   dogs: 17

One component, two modes: this is the same surface as the editable state with editable={false} — no toolbar, no caret, aria-readonly="true". The h2 uses the display serif; the link carries rel="noopener noreferrer nofollow"; inline code and the <pre> block sit on surface-2 behind a hairline; the blockquote is ruled in accent. Write mode renders through the exact same .prose, so viewer and editor never drift.

.prose
One token-based typography scale drives both modes. The editable surface is px-3.5 py-3 with focus:outline-none; the read-only render reuses it verbatim, so there is no separate viewer to drift.
headings
The block-type select emits H2 / H3 (StarterKit's exposed levels), set in the --font-display serif against sans body copy for a clear visual hierarchy.
links
The standalone @tiptap/extension-link (StarterKit's own disabled) renders an accent underline and stamps rel="noopener noreferrer nofollow"; openOnClick is off inside the editor.
code
Inline code is mono on a surface-2 chip behind a hairline; the fenced <pre> block shares the fill and scrolls horizontally — both come from StarterKit's code / codeBlock marks.
wire format
This body round-trips as markdown by default (getMarkdown()) or HTML with format="html" (getHTML()) — the render is identical; only the persisted string shape changes.

Source · RichTextEditor.tsx EditorContent prose surface (.prose, role="textbox", editable={false}aria-readonly) · Tiptap StarterKit (headings · lists · blockquote · code) + @tiptap/extension-link · tiptap-markdown round-trip · design-system/editor.