> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stackra.figentra.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 0466 — The document editor is TipTap v3 core, and packages extend it through editor contributions

> Accepted · 2026-10-28

> [!NOTE]
>
> Accepted by the owner on 2026-10-28 (design-system session c6, STA-1371), as drafted. It gates
> gap-inventory batch 2.

## Context

[0270](https://docs.stackra.figentra.com/adr/0270-builder-architecture-one-editor-kernel-document-kinds-and-collaboration-levels.md) makes `@stackra/builder`
the one editor kernel, with a "document" surface for posts, articles, help articles, product descriptions and email
templates, and full Yjs co-editing through `@stackra/collaboration`. It does not name the rich-text engine. The HeroUI Pro
rich-text editor left core with ADR 0461, so core has none. Products need Shopify-level product descriptions, Yoast-style
SEO beside the text, AI writing actions, and Markdown/MDX in and out, on web and on mobile. Weighed: TipTap v3 (ProseMirror),
Lexical, BlockNote (built on TipTap; parts GPL or commercial), Plate (Slate) and Milkdown.

## Decision

1. **Engine.** The document surface runs on **TipTap v3 core** (MIT, ProseMirror) and only its MIT packages. TipTap's paid
   cloud and Pro extensions are not used. On native the same engine runs through a TipTap-based React Native editor
   (10tap class), so one schema and one set of extensions serve web and mobile.

2. **One schema, owned by `@stackra/builder`.** Nodes and marks are declared once. The stored form is the L2 document JSON
   ([0110](https://docs.stackra.figentra.com/adr/0110-experience-is-the-sdui-service-at-l2.md)): ProseMirror JSON that references registered blocks by name,
   never markup, CSS or code ([0154](https://docs.stackra.figentra.com/adr/0154-tenant-code-runs-only-in-a-sandboxed-code-step.md)).

3. **Editor contributions.** A package extends the editor by registering contributions in its module, never by importing
   editor internals:

   * nodes and marks;
   * slash-menu commands and toolbar or bubble-menu buttons;
   * side panels (for example the SEO analysis panel);
   * input rules and paste handlers;
   * AI actions.

   A contribution names the document kinds it applies to. Contributions are UI slots in the sense of
   [0350](https://docs.stackra.figentra.com/adr/0350-additions-across-products-slots-in-app-screens-released-extension-points-rule-facts-and-enhanced-modules.md),
   and gen lists them in the manifest like other registered code.

4. **AI is a contributor, not part of the kernel.** `@stackra/ai` contributes actions: rewrite, shorten, expand, change
   tone, translate EN↔AR, summarise, generate SEO title and description, alt text, FAQ from content, and suggest category.
   Each runs as an ordinary action (permission, risk, human approval for writes, [0021](https://docs.stackra.figentra.com/adr/0021-ai-engine-and-agent-write-safety.md)).
   Its result is applied as one undoable transaction that the author accepts or rejects.

5. **Markdown and MDX are serialisers.**
   * Markdown import and export use TipTap's Markdown support, both CommonMark and GFM.
   * MDX import maps each JSX element to a registered block by name and its props through the block's Zod schema. Unknown
     elements are refused, and expressions are never evaluated.
   * MDX export writes registered blocks back as JSX.
   * HTML is accepted on paste only, sanitised to the schema.

6. **Collaboration** binds through `@stackra/collaboration` (Yjs), per 0270 decision 5. Comments use `@Commentable`
   ([0225](https://docs.stackra.figentra.com/adr/0225-realtime-drivers-co-editing-and-the-commentable-trait.md)).

7. **Design system.** The editor's chrome (toolbar, bubble menu, slash menu, block handle, link and image dialogs) is
   `@stackra/ui` components (gap-inventory row 67). `@stackra/builder` composes them; the UI kit has no editor logic.

8. **Bidi.** Every block carries `dir="auto"` unless set, and Arabic is the first-class test language for the schema,
   paste and serialisers.

## Consequences

* One engine and schema on web and mobile, with Yjs co-editing ready, and every package can add to the editor without
  forking it.
* AI and SEO arrive as contributions, so a product without them ships a smaller editor.
* We depend on ProseMirror's model and TipTap's release cadence. MDX is limited to registered blocks, by design.
* Chore: `@stackra/builder` owns the schema version and its migrations. A contribution that adds a node must ship its
  Markdown and MDX serialiser.

## Enforcement

* Planned: gen refuses a contribution whose node has no serialiser.
* Planned: `FORBIDDEN_DEPENDENCIES` adds `@tiptap-pro/*`.
* Planned: a schema round-trip test in `@stackra/builder` covers JSON ↔ Markdown ↔ MDX on an Arabic fixture.

## Amendment 2026-10-31: the native editor is tentap (STA-1371)

**Context.** Decision 1 named "a TipTap-based React Native editor (10tap class)" for native. The owner approved
`@10play/tentap-editor` and `react-native-webview` on 2026-10-31 (MIT, MIT-licensed packages only, no TipTap Pro).

**Decision.**

1. `@stackra/ui/native`'s `RichTextEditor` runs on `@10play/tentap-editor` 1.0.1 with `react-native-webview` at Expo SDK
   57's bundled version (`catalog:mobile`). Both are optional peers of `@stackra/ui`.
2. tentap ships its own prebuilt TipTap v3 editor inside the WebView page (its TenTapStartKit schema), isolated from the
   app's JavaScript and from the web editor's `catalog:frontend` TipTap. Its schema has no code block, horizontal rule,
   `dir` attribute or CharacterCount, so the wrapper strips `dir` on the way in and writes `dir: "auto"` back on every
   block on the way out (the web JSON shape, so documents round-trip), counts characters itself and puts back a change
   past the limit, and keeps a value with nodes the native schema lacks read-only, shown as its text.
3. Bidi on native is CSS inside the page (`unicode-bidi: plaintext` per block, the page's base direction from the app),
   not `dir` attributes. Editor contributions stay web-only until `@stackra/builder` builds its own tentap web bundle
   with the shared schema (tentap's `customSource`).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.