
Features:
- Rich text formatting: Bold, italic, underline, strikethrough, inline code, superscript, subscript, and more.
- Eight heading levels: Supports
heading-onethroughheading-eightin the React version, andheading-onethroughheading-sixin the Vanilla version. - Block elements: Includes blockquote, code block, and paragraph formats.
- Table editing: Supports dynamic row and column insertion directly in the editor.
- Resizable images: Accepts a custom upload handler that returns a URL, then renders images as resizable elements in the content area.
- Nested lists: Supports bulleted and numbered lists with indent and outdent controls.
- Text and background colors: Ships built-in color pickers for both font color and highlight color.
- Find and replace: Highlights search matches in the editor with navigation between occurrences.
- Multi-format export: Returns content as HTML, JSON, or plain text via
getHTML(),getJSON(), andgetText(). - Word and character count: Optional display rendered below the editor area.
- Read-only mode: Renders content for display purposes with the toolbar hidden.
- Fullscreen editing: Expands the editor to fill the viewport with a single toolbar button.
- Keyboard shortcuts: Standard shortcuts for bold, italic, underline, undo, redo, link insertion, and list indentation.
How To Use It:
Installation
React:
npm install editium
Editium requires React and ReactDOM as peer dependencies:
npm install react react-dom
Vanilla JavaScript (CDN):
The single-bundle option includes JavaScript, CSS, and icons in one file. No additional setup is needed:
<script src="https://unpkg.com/editium/vanilla/editium.bundle.js"></script>
Vanilla JavaScript (npm):
npm install editium
Then import the CSS and the Vanilla module separately:
import 'editium/vanilla/editium.css'; import Editium from 'editium/vanilla/editium.js';
Basic Setup
React:
import { Editium } from 'editium';
function App() {
return (
<Editium
placeholder="Write your article here..."
toolbar="all" // Show every available toolbar button
showWordCount={true} // Display word and character count below editor
/>
);
}
Vanilla JavaScript:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Editium Demo</title>
<!-- Load the self-contained bundle: JS + CSS + icons in one file -->
<script src="https://unpkg.com/editium/vanilla/editium.bundle.js"></script>
</head>
<body>
<div id="my-editor"></div>
<script>
// Attach the editor to a DOM element
const editor = new Editium({
container: document.getElementById('my-editor'),
placeholder: 'Write your article here...',
toolbar: 'all', // Show every available toolbar button
showWordCount: true // Display word and character count
});
</script>
</body>
</html>
Capturing Content Changes
React (controlled component):
import React, { useState } from 'react';
import { Editium } from 'editium';
function ArticleEditor() {
const [htmlContent, setHtmlContent] = useState('');
const [jsonContent, setJsonContent] = useState(null);
// onChange fires with both HTML string and JSON structure on every edit
const handleChange = (html: string, json: any) => {
setHtmlContent(html);
setJsonContent(json);
};
const handleSave = async () => {
// Post the HTML and JSON payload to your backend
await fetch('/api/articles', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ html: htmlContent, json: jsonContent })
});
};
return (
<div>
<Editium onChange={handleChange} toolbar="all" />
<button onClick={handleSave}>Publish Article</button>
</div>
);
}
Vanilla JavaScript:
const editor = new Editium({
container: document.getElementById('my-editor'),
toolbar: 'all',
onChange: (content) => {
// content.html — HTML string
// content.json — structured JSON array
console.log('HTML output:', content.html);
}
});
// Read content on demand via the API
document.getElementById('save-btn').addEventListener('click', () => {
const payload = {
html: editor.getHTML(), // Full HTML string
text: editor.getText(), // Plain text string (no markup)
json: editor.getJSON() // Slate-compatible JSON array
};
fetch('/api/articles', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
});
Loading Initial Content
React:
import { Editium } from 'editium';
function EditExistingPost() {
// Pass a Slate.js-compatible JSON array as the initial value
const savedContent = [
{
type: 'heading-one',
children: [{ text: 'My Article Title' }]
},
{
type: 'paragraph',
children: [{ text: 'Edit this paragraph to get started.' }]
}
];
return (
<Editium
initialValue={savedContent}
toolbar="all"
/>
);
}
Vanilla JavaScript:
const editor = new Editium({
container: document.getElementById('my-editor'),
toolbar: 'all'
});
// setContent() accepts an HTML string
editor.setContent('<h1>My Article Title</h1><p>Edit this paragraph to get started.</p>');
Custom Toolbar
Pass an array of toolbar item keys to display only what you need:
// React
<Editium
toolbar={[
'bold', 'italic', 'underline', 'strikethrough',
'separator',
'heading-one', 'heading-two', 'heading-three',
'separator',
'bulleted-list', 'numbered-list', 'indent', 'outdent',
'separator',
'link', 'image',
'separator',
'undo', 'redo'
]}
/>
// Vanilla JS
const editor = new Editium({
container: document.getElementById('my-editor'),
toolbar: [
'bold', 'italic', 'underline', 'strikethrough',
'separator',
'heading-one', 'heading-two', 'heading-three',
'separator',
'bulleted-list', 'numbered-list', 'indent', 'outdent',
'separator',
'link', 'image',
'separator',
'undo', 'redo'
]
});
Custom Image Upload Handler
Editium calls your upload function with the selected File object and expects a resolved URL string in return:
React:
import { Editium } from 'editium';
function EditorWithUpload() {
const handleImageUpload = async (file: File): Promise<string> => {
const form = new FormData();
form.append('file', file); // Append the file to a FormData payload
const res = await fetch('/api/media', {
method: 'POST',
body: form
});
const data = await res.json();
return data.url; // Return the CDN URL for the uploaded image
};
return (
<Editium
onImageUpload={handleImageUpload}
toolbar="all"
/>
);
}
Vanilla JavaScript:
const editor = new Editium({
container: document.getElementById('my-editor'),
toolbar: 'all',
onImageUpload: async (file) => {
const form = new FormData();
form.append('file', file);
const res = await fetch('/api/media', {
method: 'POST',
body: form
});
const data = await res.json();
return data.url; // Return the CDN URL for the uploaded image
}
});
Read-Only Mode
Use read-only mode to display stored rich text as a formatted view:
// React
<Editium
initialValue={storedJsonContent}
readOnly={true}
toolbar={[]} // Pass an empty array to hide the toolbar entirely
/>
// Vanilla JS
const viewer = new Editium({
container: document.getElementById('article-body'),
readOnly: true,
toolbar: [] // Pass an empty array to hide the toolbar entirely
});
viewer.setContent(storedHtml);
Height Configuration
Heights accept either a string with a CSS unit or a plain number (converted to px):
// React
<Editium
height={500} // Sets default height to 500px
minHeight={250} // Editor won't shrink below 250px
maxHeight={800} // Editor scrolls beyond 800px
/>
// Vanilla JS
const editor = new Editium({
container: document.getElementById('my-editor'),
height: '500px',
minHeight: '250px',
maxHeight: '800px'
});
Custom Styling
Editium exposes CSS class hooks for all its structural elements:
/* Wrapper around the entire editor */
.editium-wrapper {
border: 2px solid #4f46e5;
border-radius: 6px;
font-family: 'Inter', sans-serif;
}
/* Toolbar bar */
.editium-toolbar {
background-color: #f8f8f8;
border-bottom: 1px solid #e5e7eb;
}
/* Toolbar button hover and active states */
.editium-toolbar button:hover {
background-color: #e0e7ff;
}
.editium-toolbar button.active {
background-color: #4f46e5;
color: white;
}
/* Editable content area */
.editium-editor {
padding: 24px;
font-size: 16px;
line-height: 1.75;
}
Vanilla JS API Methods
// Returns the full HTML string of the current editor content
editor.getHTML();
// Returns a plain text version of the content, with all markup stripped
editor.getText();
// Returns the Slate-compatible JSON array representing the document structure
editor.getJSON();
// Replaces the editor content with the provided HTML string
editor.setContent('<p>Replacement content goes here.</p>');
// Clears all content from the editor
editor.clear();
// Moves focus to the editor area
editor.focus();
// Removes the editor from the DOM and cleans up event listeners
editor.destroy();
Configuration Reference
React Props
initialValue(string | CustomElement[]): Sets the editor’s starting content. Accepts an HTML string or a Slate-compatible JSON array. Defaults to a single empty paragraph.onChange((html: string, json: CustomElement[]) => void): Fires on every content change. Receives the HTML string and the JSON array.toolbar(ToolbarItem[] | ‘all’): Accepts'all'to show every button, or an array of item key strings to show a custom set.placeholder(string): Text shown in the editor area when content is empty. Defaults to'Start typing...'.className(string): Adds a custom CSS class to the outer wrapper element.style(React.CSSProperties): Applies inline styles to the outer wrapper element.readOnly(boolean): Puts the editor in display-only mode. Defaults tofalse.onImageUpload((file: File) => Promise<string>): Receives the selectedFileobject and must return a resolved URL string.searchQuery(string): The active search term for match highlighting.searchMatches(Array): The array of match locations returned by the find-replace feature.currentMatchIndex(number): The index of the currently highlighted search match.showWordCount(boolean): Displays the word and character count below the editor. Defaults totrue.height(string | number): Sets the default editor height. Defaults to'200px'.minHeight(string | number): Sets the minimum height before content causes the editor to shrink. Defaults to'150px'.maxHeight(string | number): Sets the maximum height before the editor area scrolls. Defaults to'250px'.
Vanilla JS Options
container(HTMLElement): The DOM element to mount the editor into. Required.placeholder(string): Text shown when the editor is empty. Defaults to''.toolbar(string | array): Accepts'all'or an array of item key strings. Defaults to'all'.showWordCount(boolean): Displays the word and character count. Defaults tofalse.readOnly(boolean): Puts the editor in display-only mode. Defaults tofalse.className(string): Adds a custom CSS class to the wrapper element.height(string | number): Default editor height. Defaults to'200px'.minHeight(string | number): Minimum height. Defaults to'150px'.maxHeight(string | number): Maximum height before scrolling. Defaults to'250px'.onChange(function): Fires on every content change. Receives an object withhtml,text, andjsonproperties.onImageUpload(function): Receives theFileobject and must return a resolved URL string.
Toolbar Item Keys
All available item keys: bold, italic, underline, strikethrough, code, superscript, subscript, heading-one, heading-two, heading-three, heading-four, heading-five, heading-six, heading-seven (React only), heading-eight (React only), paragraph, blockquote, code-block, bulleted-list, numbered-list, indent, outdent, left, center, right, justify, text-color, bg-color, link, image, table, horizontal-rule, undo, redo, find-replace, fullscreen, view-output, separator.
Keyboard Shortcuts
| Shortcut | Action |
|---|---|
Ctrl/Cmd + B |
Bold |
Ctrl/Cmd + I |
Italic |
Ctrl/Cmd + U |
Underline |
Ctrl/Cmd + Z |
Undo |
Ctrl/Cmd + Y |
Redo |
Ctrl/Cmd + K |
Insert link |
F11 |
Toggle fullscreen |
Ctrl/Cmd + F |
Open find and replace |
Tab |
Indent list item |
Shift + Tab |
Outdent list item |
Alternatives
- 10 Best WYSIWYG Editors For Easier Content Editing
- 10 Best WYSIWYG Markdown Editors For Faster Writing
The post Rich Text WYSIWYG Editor for React & Vanilla JS – Editium appeared first on CSS Script.
Discover more from RSS Feeds Cloud
Subscribe to get the latest posts sent to your email.
