A lightweight, powerful rich text editor built with pure vanilla JavaScript. Zero dependencies, framework-agnostic, and production-ready.
- Zero Dependencies - Pure vanilla JavaScript, no external frameworks required
- Lightweight - Minimal footprint with maximum functionality
- Rich Text Editing - Comprehensive formatting options (bold, italic, underline, strikethrough, etc.)
- Advanced Features - Tables, images, code blocks, and more
- Customizable - Flexible toolbar and styling options
- Production Ready - Battle-tested and reliable
- Multiple Formats - Export to HTML, plain text, or JSON
- Keyboard Shortcuts - Efficient editing with standard shortcuts
- Responsive - Works seamlessly on all screen sizes
- Accessible - ARIA support and keyboard navigation
Single Bundle - All-in-one file including JavaScript, CSS, and icons:
<script src="https://unpkg.com/editium/vanilla/editium.bundle.js"></script>Alternative CDNs:
<!-- jsDelivr -->
<script src="https://cdn.jsdelivr.net/npm/editium/vanilla/editium.bundle.js"></script>Separate Files - For more control:
<!-- unpkg -->
<link rel="stylesheet" href="https://unpkg.com/editium/vanilla/editium.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/emoji-picker-element@^1/index.js"></script>
<script src="https://unpkg.com/editium/vanilla/editium.js"></script>
<!-- jsDelivr -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/editium/vanilla/editium.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/emoji-picker-element@^1/index.js"></script>
<script src="https://cdn.jsdelivr.net/npm/editium/vanilla/editium.js"></script>npm install editiumimport 'editium/vanilla/editium.css';
import Editium from 'editium/vanilla/editium.js';
const editor = new Editium({
container: document.getElementById('editor'),
placeholder: 'Start typing...',
toolbar: 'all'
});Download the files from the GitHub repository and include them in your project:
<link rel="stylesheet" href="path/to/editium.css">
<script src="path/to/editium.js"></script><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Editium Editor</title>
<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',
showWordCount: true
});
</script>
</body>
</html>const editor = new Editium({
container: document.getElementById('editor'),
placeholder: 'Start typing...',
toolbar: 'all',
showWordCount: true,
readOnly: false,
className: 'custom-class',
height: '300px',
minHeight: '200px',
maxHeight: '400px',
onChange: (content) => {
console.log('Content changed:', content);
},
onImageUpload: async (file) => {
const url = await uploadToServer(file);
return url;
}
});| Option | Type | Default | Description |
|---|---|---|---|
container |
HTMLElement | required | DOM element to attach the editor |
placeholder |
string | '' |
Placeholder text when editor is empty |
toolbar |
string | array | 'all' |
Toolbar configuration ('all' or array of items) |
showWordCount |
boolean | false |
Display word and character count |
readOnly |
boolean | false |
Make editor read-only |
className |
string | '' |
Custom CSS class for wrapper |
height |
string | number | '200px' |
Default editor height |
minHeight |
string | number | '150px' |
Minimum height before content shrinks |
maxHeight |
string | number | '250px' |
Maximum height before scrolling |
onChange |
function | null |
Callback when content changes |
onImageUpload |
function | null |
Custom image upload handler |
Heights can be specified as strings ('300px', '20rem', '50vh') or numbers (300 converts to '300px').
const editor = new Editium({
container: document.getElementById('editor'),
height: 400,
minHeight: 200,
maxHeight: 600
});toolbar: 'all'toolbar: [
'bold', 'italic', 'underline',
'separator',
'heading-one', 'heading-two',
'separator',
'bulleted-list', 'numbered-list',
'separator',
'link', 'image', 'table',
'separator',
'undo', 'redo'
]bold,italic,underline,strikethroughcode,superscript,subscript
paragraphheading-one,heading-two,heading-three,heading-four,heading-five,heading-sixblockquote,code-block
left,center,right,justify
text-color,bg-color
bulleted-list,numbered-listindent,outdent
link,image,table,horizontal-rule
undo,redo
preview,view-html,view-json,find-replace,fullscreen
separator
// Get content
const html = editor.getHTML();
const text = editor.getText();
const json = editor.getJSON();
// Set content
editor.setContent('<p>New content</p>');
// Clear and focus
editor.clear();
editor.focus();
// Cleanup
editor.destroy();<div id="basic-editor"></div>
<script>
const basicEditor = new Editium({
container: document.getElementById('basic-editor'),
placeholder: 'Write something...',
toolbar: ['bold', 'italic', 'underline', 'separator', 'link']
});
</script><div id="full-editor"></div>
<script>
const fullEditor = new Editium({
container: document.getElementById('full-editor'),
placeholder: 'Start writing your document...',
toolbar: 'all',
showWordCount: true,
onChange: (content) => {
console.log('Content updated:', content.html);
}
});
</script><div id="viewer"></div>
<script>
const viewer = new Editium({
container: document.getElementById('viewer'),
readOnly: true,
toolbar: []
});
viewer.setContent('<h1>Document Title</h1><p>Document content...</p>');
</script><div id="editor-with-upload"></div>
<script>
const editorWithUpload = new Editium({
container: document.getElementById('editor-with-upload'),
toolbar: 'all',
onImageUpload: async (file) => {
const formData = new FormData();
formData.append('image', file);
const response = await fetch('/api/upload', {
method: 'POST',
body: formData
});
const data = await response.json();
return data.url;
}
});
</script><div id="editor"></div>
<button onclick="saveContent()">Save</button>
<script>
const editor = new Editium({
container: document.getElementById('editor'),
toolbar: 'all'
});
function saveContent() {
const content = {
html: editor.getHTML(),
text: editor.getText(),
json: editor.getJSON()
};
localStorage.setItem('editorContent', JSON.stringify(content));
// Or send to server
fetch('/api/save', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(content)
});
}
// Load saved content
const savedContent = localStorage.getItem('editorContent');
if (savedContent) {
const content = JSON.parse(savedContent);
editor.setContent(content.html);
}
</script>Ctrl/Cmd + B- BoldCtrl/Cmd + I- ItalicCtrl/Cmd + U- UnderlineCtrl/Cmd + Z- UndoCtrl/Cmd + Y- RedoF11- Toggle fullscreenCtrl/Cmd + F- Find & Replace
Custom styling example:
/* Customize wrapper */
.editium-wrapper {
border: 2px solid #007bff;
border-radius: 8px;
}
/* Customize toolbar */
.editium-toolbar {
background-color: #f0f0f0;
}
/* Customize editor area */
.editium-editor {
min-height: 300px;
font-size: 16px;
line-height: 1.8;
}
/* Custom placeholder color */
.editium-editor:empty:before {
color: #999;
}- Chrome (latest)
- Firefox (latest)
- Safari (latest)
- Edge (latest)
- NPM Package: https://www.npmjs.com/package/editium
- GitHub Repository: https://github.com/NabarupDev/Editium
- Issues: https://github.com/NabarupDev/Editium/issues
- unpkg CDN: https://unpkg.com/editium/vanilla/
- jsDelivr CDN: https://cdn.jsdelivr.net/npm/editium/vanilla/
MIT License - See LICENSE file for details.
Contributions are welcome! Please submit a Pull Request.
Made with ❤️ by NabarupDev