Production-ready rich text editor for React and Vanilla JavaScript
Modern • Lightweight • Customizable • Zero Dependencies (Vanilla)
Editium is a flexible rich text editor that works seamlessly in both React and Vanilla JavaScript environments. Built for developers who need a reliable, feature-rich editor without the complexity.
Why Editium?
- Dual-Mode Support: Same powerful features in React (Slate.js) and Vanilla JS (pure JavaScript)
- Production Ready: Battle-tested with comprehensive formatting tools and advanced features
- Developer Experience: Get from npm install to working editor in under 60 seconds
- Export Flexibility: HTML, JSON, and plain text output formats
- Fully Customizable: Configure exactly what you need, hide what you don't
npm install editiumimport { Editium } from 'editium';
function App() {
return <Editium placeholder="Start typing..." toolbar="all" />;
}Single file - no build step required:
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/editium/vanilla/editium.bundle.js"></script>
</head>
<body>
<div id="editor"></div>
<script>
const editor = new Editium({
container: document.getElementById('editor'),
placeholder: 'Start typing...',
toolbar: 'all'
});
</script>
</body>
</html>Rich Text Editing
- Comprehensive formatting: bold, italic, underline, strikethrough, code
- 8 heading levels, blockquotes, and code blocks
- Text and background colors
- Superscript and subscript
Advanced Capabilities
- Full table support with dynamic rows/columns
- Resizable images with custom upload handlers
- Bulleted and numbered lists with nesting
- Find and replace with match highlighting
- Text alignment (left, center, right, justify)
Developer Experience
- TypeScript support with full type definitions
- HTML and JSON export formats
- Customizable toolbar (show only what you need)
- Keyboard shortcuts for efficient editing
- Read-only mode for content display
- Word and character counting
- Fullscreen editing mode
Framework Flexibility
- React: Component-based with hooks support
- Vanilla JS: Zero dependencies, works anywhere
- Same API and features across both versions
npm install editiumPeer dependencies (React only):
npm install react react-domCDN (Vanilla JS):
<script src="https://unpkg.com/editium/vanilla/editium.bundle.js"></script>Basic Example
import { Editium } from 'editium';
function App() {
return <Editium toolbar="all" placeholder="Start typing..." />;
}With Content Management
import React, { useState } from 'react';
import { Editium } from 'editium';
function Editor() {
const [content, setContent] = useState({ html: '', json: [] });
return (
<Editium
toolbar="all"
onChange={(html, json) => setContent({ html, json })}
showWordCount={true}
/>
);
}Custom Toolbar
<Editium
toolbar={[
'bold', 'italic', 'underline',
'separator',
'heading-one', 'heading-two',
'separator',
'bulleted-list', 'numbered-list',
'link', 'image'
]}
/>CDN (Recommended)
<script src="https://unpkg.com/editium/vanilla/editium.bundle.js"></script>
<div id="editor"></div>
<script>
const editor = new Editium({
container: document.getElementById('editor'),
toolbar: 'all',
placeholder: 'Start typing...'
});
// Get content
const html = editor.getHTML();
const json = editor.getJSON();
</script>NPM
import 'editium/vanilla/editium.css';
import Editium from 'editium/vanilla/editium.js';
const editor = new Editium({
container: document.getElementById('editor'),
toolbar: 'all'
});→ Full Vanilla JS Documentation
| Prop | Type | Default | Description |
|---|---|---|---|
toolbar |
ToolbarItem[] | 'all' |
Basic items | Toolbar configuration |
placeholder |
string |
'Start typing...' |
Placeholder text |
onChange |
(html, json) => void |
- | Content change callback |
initialValue |
string | CustomElement[] |
- | Initial content |
readOnly |
boolean |
false |
Read-only mode |
showWordCount |
boolean |
false |
Show word/character count |
height |
string | number |
'200px' |
Editor height |
onImageUpload |
(file: File) => Promise<string> |
- | Custom image upload |
| Option | Type | Default | Description |
|---|---|---|---|
container |
HTMLElement |
required | DOM element for editor |
toolbar |
string | array |
'all' |
Toolbar configuration |
placeholder |
string |
'' |
Placeholder text |
onChange |
function |
- | Content change callback |
readOnly |
boolean |
false |
Read-only mode |
showWordCount |
boolean |
false |
Show word/character count |
height |
string | number |
'200px' |
Editor height |
onImageUpload |
function |
- | Custom image upload |
editor.getHTML() // Returns HTML string
editor.getText() // Returns plain text
editor.getJSON() // Returns JSON structure
editor.setContent(html) // Set editor content
editor.clear() // Clear editor
editor.focus() // Focus editor
editor.destroy() // Cleanup editorAvailable items: bold, italic, underline, strikethrough, code, superscript, subscript, heading-one through heading-eight, 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
React:
const handleImageUpload = async (file: File) => {
const formData = new FormData();
formData.append('image', file);
const response = await fetch('/api/upload', {
method: 'POST',
body: formData
});
const { url } = await response.json();
return url;
};
<Editium onImageUpload={handleImageUpload} />Vanilla JS:
const editor = new Editium({
container: document.getElementById('editor'),
onImageUpload: async (file) => {
const formData = new FormData();
formData.append('image', file);
const response = await fetch('/api/upload', {
method: 'POST',
body: formData
});
const { url } = await response.json();
return url;
}
});React:
function EditorWithSave() {
const [content, setContent] = useState({ html: '', json: [] });
const handleSave = async () => {
await fetch('/api/save', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(content)
});
};
return (
<>
<Editium onChange={(html, json) => setContent({ html, json })} />
<button onClick={handleSave}>Save</button>
</>
);
}Vanilla JS:
const editor = new Editium({
container: document.getElementById('editor'),
onChange: (content) => {
localStorage.setItem('content', JSON.stringify({
html: content.html,
json: content.json
}));
}
});// React
<Editium height={400} minHeight={200} maxHeight={600} />
// Vanilla JS
new Editium({
container: document.getElementById('editor'),
height: '400px',
minHeight: '200px',
maxHeight: '600px'
});| 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 |
Fullscreen |
Tab |
Indent list |
Shift + Tab |
Outdent list |
- Chrome (latest)
- Firefox (latest)
- Safari (latest)
- Edge (latest)
Get Help
- GitHub Issues - Bug reports and feature requests
- GitHub Discussions - Questions and community support
- Security: See
SECURITY.mdfor responsible disclosure and contact instructions
Contributing
We welcome contributions! Please see our Contributing Guide for details.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Code of Conduct
This project follows the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code.
MIT License - See LICENSE file for details.
Copyright © 2025 Nabarup Dev
- Built with Slate.js for the React version
- Inspired by modern rich text editors: TipTap, ProseMirror, and Quill
Made with ❤️ by Nabarup Dev
⭐ Star us on GitHub if you find this project useful!