A Svelte rich text editor that is just an action.
use:richTextEditormounts the editor on any element and hands you a controller. It is a plain Svelte action with no compiler coupling, so the same code runs on Svelte 3, 4 and 5 — and in SvelteKit once you mount it on the client. One engine underneath: AI Toolkit, per-node CRDT collaboration, tracked changes, and clean HTML output.
Your markup, your toolbar, your styles.
onUpdate hands you a state snapshot (bold, canUndo, …) that drives class:is-active on your own buttons.Install once, attach with use:
One npm package ships the engine, the Svelte action, and the plugin bundle. Svelte is not a dependency of the package at all — the action is framework-agnostic DOM code.
npm install @richscripts/richtexteditor
Option 1 — bring your own UI
The action mounts a chrome-less editing surface and gives you the controller through onReady. Build the toolbar out of your own components and bind them to the state snapshot. Use on:mousedown|preventDefault so a toolbar click never steals the caret from the editor.
<script>
import { richTextEditor } from "@richscripts/richtexteditor/svelte";
let editor; // the controller, once it is ready
let state = {}; // active formats, refreshed as the caret moves
</script>
<div class="toolbar">
<button class:is-active={state.bold}
on:mousedown|preventDefault={() => editor.run("bold")}>B</button>
<button class:is-active={state.italic}
on:mousedown|preventDefault={() => editor.run("italic")}>I</button>
<button disabled={!state.canUndo}
on:mousedown|preventDefault={() => editor.run("undo")}>Undo</button>
</div>
<div use:richTextEditor={{
value: "<p>Draft your update...</p>",
onReady: (e) => (editor = e),
onUpdate: (s) => (state = s)
}}></div>Reading and writing content
The controller exposes HTML, plain text, Markdown, and the structured JSON document model, plus statistics, focus, and a destroy that the action already calls for you when the node unmounts. Changing the value you pass to the action pushes new content into the editor, so a Svelte store can own the document.
<script>
import { richTextEditor } from "@richscripts/richtexteditor/svelte";
let html = "<p>Hello</p>";
let editor;
// The action's update() pushes a changed `value` back into the editor,
// so a store or a parent prop can drive the document.
function save() {
html = editor.getHTML(); // publish-ready markup
const doc = editor.getJSON(); // structured document model
const md = editor.getMarkdown();
}
</script>
<div use:richTextEditor={{ value: html, onReady: (e) => (editor = e) }}></div>
<button on:click={save}>Save</button>Option 2 — the full editor with its own toolbar
If you want the shipped toolbar, ribbon, and dialogs rather than your own, skip the action and construct the editor directly in onMount. In SvelteKit keep this in onMount (or a browser guard) so it never runs during server rendering.
<script>
import { onMount, onDestroy } from "svelte";
let host;
let editor;
onMount(async () => {
// rte.js registers the global constructor and the plugin bundle.
await import("@richscripts/richtexteditor");
editor = new RichTextEditor(host, { height: 420 });
});
onDestroy(() => editor?.destroy?.());
</script>
<div bind:this={host}></div>editor.run().Structured JSON demoThe document model behind getJSON.AI Toolkit demoAsk AI, AI Chat, and inline review with your own key.Why teams pick it over assembling an editor stack
- Everything is included: AI Toolkit (bring your own key), per-node Yjs CRDT collaboration, tracked changes, comments, and revision history ship in the same package — no premium add-on tiers.
- Clean HTML out: publish-ready markup plus a structured JSON model for validation and server rendering via the package’s
serverentry. - Perpetual license from $129: no subscription and no per-seat AI pricing — see pricing and the Tiptap / Quill comparisons.
Using another framework? There are matching guides for React, Next.js, Vue, Angular, and Blazor, and plain JavaScript.