A rich text editor built to fit the Next.js App Router.
Run the editor in a client component, render saved content on the server without a DOM, and skip the hydration pitfalls. This documentation site is itself a Next.js app running the editor on every demo page, so the guidance here is what we ship.
App Router, SSR, and RSC — handled.
"use client" surface; your Server Components fetch the content and pass it down as a prop.server entry turns the structured JSON document into HTML with no browser — perfect for the published/read view.editor.destroy() on cleanup, so React 18 StrictMode’s double-invoke does not leak.Install the package
One npm package ships the engine, the React bindings, and the plugin bundle. React 18+ is a peer dependency, which the Next.js App Router already provides.
npm install @richscripts/richtexteditor
1. Wrap the editor in a client component
The editor mounts into a live DOM and manages its own toolbars and iframe, so it belongs in a component marked "use client". Keep the component small — it just renders the editor and takes the initial content as a prop.
"use client";
// The editor renders into a live DOM, so it must run in a client component.
// Server components pass the initial HTML down as a prop.
import { RichTextEditor } from "@richscripts/richtexteditor/react";
export default function EditorClient({ initialHtml }: { initialHtml: string }) {
return <RichTextEditor defaultValue={initialHtml} config={{ height: 480 }} />;
}2. Fetch content in a Server Component, pass it down
Your route stays a Server Component: it loads the document with your data layer and hands the HTML to the client editor. No editor code runs on the server for the editing view.
// app/edit/[id]/page.tsx — a Server Component
import EditorClient from "./EditorClient";
export default async function EditPage({ params }: { params: { id: string } }) {
const doc = await loadDocument(params.id); // your data layer
return <EditorClient initialHtml={doc.html} />;
}3. Render saved content on the server for the read view
For the published page — where visitors read the content but do not edit — you do not need the editor at all. The package’s server entry converts the structured JSON document to an HTML string with no DOM, so it works in a Server Component or a route handler.
// app/post/[slug]/page.tsx — render SAVED content on the server, no DOM needed
import { renderHTML } from "@richscripts/richtexteditor/server";
export default async function PostPage({ params }: { params: { slug: string } }) {
const post = await loadPost(params.slug); // { json: structured document }
const html = renderHTML(post.json); // structured JSON -> HTML string
return <article dangerouslySetInnerHTML={{ __html: html }} />;
}The re-render gotcha (and why the component avoids it)
RichTextEditor replaces its host element’s children with its own chrome. If you mount the raw engine onto a dangerouslySetInnerHTML host and a parent re-renders (for example setState right after mount), React re-applies the initial HTML and wipes the live editor. The supported <RichTextEditor> component handles this for you; if you build your own wrapper, memoize the host so React never re-applies its markup:
"use client";
import { memo, useEffect, useRef } from "react";
import { RichTextEditor } from "@richscripts/richtexteditor/react";
// The <RichTextEditor> component already handles this. Only relevant if you
// mount the raw engine yourself onto a dangerouslySetInnerHTML host: memoize
// the host so a parent re-render (e.g. setState after mount) cannot re-apply
// the initial HTML and wipe the live editor.
const Host = memo(function Host({ hostRef }: { hostRef: React.RefObject<HTMLDivElement | null> }) {
return <div ref={hostRef} dangerouslySetInnerHTML={{ __html: "<p></p>" }} />;
});renderHTML turns into HTML.Download & startersSample apps, including a React starter, in the bundle.Why teams pick it for Next.js products
- Everything is included: AI Toolkit (bring your own key), per-node Yjs CRDT collaboration, tracked changes, comments, and revision history are part of the license — not premium add-ons.
- Server rendering built in: the same structured document you edit renders to static HTML on the server for fast, SEO-friendly published pages.
- Perpetual license from $129: no per-seat AI pricing and no subscription — see pricing and the Tiptap / Lexical comparisons.