Rich Text Editor for CMS
Scribe Editor is the lightweight, XSS-safe WYSIWYG editor built for CMS content fields. Under 50KB, clean HTML output, headless CMS ready, and a simple getHTML() / setHTML() round-trip API. Works with Contentful, Sanity, Strapi, and custom backends.
Why CMS teams choose Scribe
Under 50KB — fast on every page
CMS admin interfaces load for every content edit. A 50KB editor vs a 400KB one means faster admin pages and happier editors.
Safe HTML output
Built-in XSS sanitization strips unsafe tags and attributes before they reach your database. No extra DOMPurify setup required.
getHTML() / setHTML() — simple round-trip
Fetch content from your API with setHTML(). Save it back with getHTML(). Clean, semantic HTML that renders anywhere.
Headless CMS ready
Works with Contentful, Sanity, Strapi, Directus, and any API-first CMS. Store HTML in a text field and render it directly.
Basic CMS Integration
Attach Scribe to any content field. Use setHTML() to load and getHTML() to save — the complete CMS round-trip.
import { Scribe } from 'scribejs-editor';
import 'scribejs-editor/dist/scribe.css';
// Initialize on the CMS content field
const editor = Scribe.init('#cms-content', {
toolbar: 'floating',
placeholder: 'Write your content...',
onChange: (html) => {
// Sync to hidden input for traditional form submit
document.querySelector('#content-hidden').value = html;
},
});
// Load existing content from your CMS API
async function loadPost(postId) {
const res = await fetch(`/api/posts/${postId}`);
const data = await res.json();
editor.setHTML(data.content);
}
// Save back to your CMS
async function savePost(postId) {
const html = editor.getHTML(); // clean, sanitized HTML
await fetch(`/api/posts/${postId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ content: html }),
});
}React CMS Component
A reusable React component for your CMS admin panel with auto-save and media picker integration.
// React CMS editor component
import { useRef, useEffect, useCallback } from 'react';
import { Scribe } from 'scribejs-editor';
export function CmsEditor({ postId, initialContent, onSave }) {
const containerRef = useRef(null);
const editorRef = useRef(null);
useEffect(() => {
editorRef.current = Scribe.init(containerRef.current, {
toolbar: 'floating',
onChange: (html) => onSave?.(postId, html),
});
editorRef.current.setHTML(initialContent ?? '');
return () => editorRef.current?.destroy();
}, [postId]);
const insertImage = useCallback((url, alt) => {
editorRef.current?.insertHTML(`<img src="${url}" alt="${alt}" />`);
}, []);
return (
<div>
<div ref={containerRef} className="prose max-w-none" />
<MediaPicker onSelect={insertImage} />
</div>
);
}Headless CMS Integration
Works with Contentful, Sanity, Strapi, Directus, or any API-first platform. Store clean HTML in a text field — no special rendering library required.
// Headless CMS integration — Contentful / Sanity / Strapi
import { Scribe } from 'scribejs-editor';
const editor = Scribe.init('#content', {
toolbar: 'fixed',
autofocus: true,
onChange: debounce(syncToCms, 1500),
});
// Load from Sanity (or any CMS)
const entry = await client.getEntry(entryId);
editor.setHTML(renderRichText(entry.fields.body)); // or raw HTML field
async function syncToCms(html) {
// Push clean HTML back to your CMS content field
await client.updateEntry({ sys: { id: entryId }, fields: { body: html } });
showSavedToast();
}
function debounce(fn, delay) {
let t;
return (...args) => { clearTimeout(t); t = setTimeout(() => fn(...args), delay); };
}Everything a CMS editor needs
Replacing TinyMCE or CKEditor in your CMS?
Many CMS projects start with TinyMCE or CKEditor 5 and later discover the cost: a 400KB+ bundle, a commercial license requirement (CKEditor 5 went GPL in 2023), and a complex config API. Scribe covers the same core use cases at 50KB with zero license restrictions.
Build your CMS editor in minutes.
No license key. No heavy bundle. Just clean HTML in, clean HTML out. Free forever under MIT.
CMS editor — common questions
What is the best lightweight rich text editor for a CMS?
Scribe Editor is an excellent choice for CMS projects. It is under 50KB gzipped (vs TinyMCE at 400KB or CKEditor 5 at 200-400KB), outputs clean sanitized HTML, has a simple setHTML() / getHTML() API for CMS round-trips, and is fully free under MIT with no license key required.
Can Scribe Editor be used with a headless CMS like Contentful or Sanity?
Yes. Scribe outputs clean HTML that can be stored in any text field in Contentful, Sanity, Strapi, Directus, or custom APIs. Use setHTML() to load content from the CMS and getHTML() to save it back. The output is fully rendered in any browser without extra processing.
Is Scribe's HTML output safe to store and render in a CMS?
Yes. Scribe Editor has built-in XSS sanitization that strips dangerous tags, event handlers, and unsafe URL schemes from all content — including pasted content from Word or Google Docs. You can render the output HTML directly in your frontend without additional sanitization.
Does Scribe Editor work as a TinyMCE replacement in a CMS?
Yes. Scribe is a direct TinyMCE replacement for most CMS use cases: headings, lists, bold/italic, links, images, and paste from Word. It is 8x smaller (50KB vs 400KB), fully free under MIT (no commercial license required), and has a simpler API.
Also compare Scribe with:
Use Scribe in your framework:
Popular use cases: