A free, accessible rich text editor (WYSIWYG) for React and the web.
Modular plugins, light and dark themes, TypeScript types. MIT licensed.
Try it in your browser Β· Docs Β· Web demo Β· Storybook Β· Releases Β· npm
npm install @editora/react @editora/core @editora/plugins @editora/themes react react-domimport { useState } from 'react';
import { EditoraEditor } from '@editora/react';
import {
BoldPlugin,
HeadingPlugin,
HistoryPlugin,
ItalicPlugin,
LinkPlugin,
ListPlugin,
UnderlinePlugin,
} from '@editora/plugins/lite';
import '@editora/themes/themes/default.css';
import '@editora/plugins/styles.css';
// Create the plugins once, outside the component (or with useMemo), so the editor is not rebuilt on every render.
const plugins = [
HeadingPlugin(),
BoldPlugin(),
ItalicPlugin(),
UnderlinePlugin(),
ListPlugin(),
LinkPlugin(),
HistoryPlugin(),
];
const toolbar = {
items: ['undo', 'redo', 'heading', 'bold', 'italic', 'underline', 'link', 'bullist', 'numlist'],
};
export default function App() {
const [html, setHtml] = useState('<h2>Launch briefing</h2><p>Start writing, or paste something in.</p>');
return (
<EditoraEditor
value={html}
onChange={setHtml}
plugins={plugins}
toolbar={toolbar}
placeholder="Start writing..."
/>
);
}Add plugins and the toolbar grows with them. The same editor is available as a web component for plain HTML, Vue, Angular and Svelte (@editora/core). Free alternative to TinyMCE, Quill, Draft.js and Slate: see an honest comparison, including when not to use Editora.
Also available: a CodeSandbox and an editor example.
- 30+ Free Plugins: Table editor, code highlighting, accessibility checker, media manager, and more
- 33+ Keyboard Shortcuts: Professional editing speed
- Enterprise-Grade: Security, performance, accessibility (WCAG compliant)
- Open Source: MIT licensed, completely free forever
- No Subscriptions: No paywalls, no limitations, no hidden costs
- β Rich Text Formatting: Bold, italic, underline, strikethrough
- β Headings: H1-H6 with proper semantic structure
- β Lists: Ordered and unordered lists with nesting
- β Blockquotes: Quoted content blocks
- β Links: URL management with validation
- β Media: An advanced media manager for images, video, audio and embeds: library, uploads, image editing, captions
- β Tables: Full table editing with resize and merge
- β Code Blocks: Syntax highlighting for 30+ languages
- β History: Undo/redo with configurable depth
- β Status Bar: Real-time cursor position, word/character counts, and selection info
- β Security: XSS protection, HTML sanitization, content validation
- β Performance: Transaction batching, memory management, monitoring
- β Theming: CSS variables, light/dark themes, runtime switching
- β Accessibility: WCAG compliance, keyboard navigation, a11y checker
- β TypeScript: Full type safety and IntelliSense
- β Framework Agnostic: Core works with any framework
- β Plugin Architecture: Everything is modular and extensible
- β Clean APIs: Intuitive hooks and component interfaces
- β Modern Stack: React 18, TypeScript 5, modern build tools
- β Tree Shaking: Optimized bundle sizes
- β SSR Compatible: Next.js and server-side rendering support
- β
500+ Ready-to-Use Icons: Generic UI icons, product icons, and logo icons via
@editora/iconsand@editora/react-icons
Images, video, audio and embedded players go through one Media window instead of a bare file picker. It works with no backend at all (files stay in the document, and a library of what you uploaded is kept in the browser), and with your own storage through one function or a full provider.
- One window for all media: Library, Upload, From URL, Stock photos and Embed (YouTube and Vimeo) in a sidebar; All / Images / Video / Audio pills; search, sort and a grid or list layout.
- Uploads you can see: drop or paste files anywhere in the window and they appear in the grid with their own progress, cancel and retry. Paste or drop a picture straight into the document and it gets a placeholder where it will land.
- Edit in place: rotate, flip, crop to a shape, scale and re-encode with the built-in image editor, and keep the original.
- Accessible by design: alt text with a "decorative" switch and an optional Alt button that calls your own description service, captions as real
<figure><img><figcaption>, keyboard control of the grid, the toolbar and resizing. - Bring your own backend:
uploadHandler(file, { onProgress, signal }), aproviderwithlist,updateanddelete, or the REST API inapi/. Stock photo services plug in the same way. - Everywhere: touch handles, a bottom sheet on phones, light and dark themes, tested in Chromium, Firefox and WebKit.
import { MediaManagerPlugin } from "@editora/plugins";
MediaManagerPlugin({
uploadHandler: async (file, { onProgress, signal }) => (await myUpload(file, onProgress, signal)).url,
optimizeImages: { maxWidth: 1600, quality: 0.85 },
});See the media manager guide for providers, stock photos, suggested alt text, galleries and the REST API.
npm install @editora/react @editora/core @editora/plugins @editora/themes react react-domMinimal React setup (no optional plugin/theme bundles):
npm install @editora/react @editora/core react react-domBundle-size note: Choose the import strategy based on your use case:
@editora/pluginsfor the full catalog@editora/plugins/litefor common/core plugins@editora/plugins/enterprisefor advanced/specialized workflows- Per-plugin subpaths (for example
@editora/plugins/bold,@editora/plugins/spell-check) for the smallest bundles
All three entry paths (full, lite, enterprise) are completely free and fully customizable.
Use the enterprise preset when you need advanced workflows (all free + customizable):
- Collaboration/workflow:
MentionPlugin,TrackChangesPlugin,VersionDiffPlugin,CommentsPlugin,ApprovalWorkflowPlugin - Validation/compliance:
ContentRulesPlugin,DocSchemaPlugin,A11yCheckerPlugin,SpellCheckPlugin,PIIRedactionPlugin - Structured/dynamic authoring:
ConditionalContentPlugin,DataBindingPlugin,MergeTagPlugin,TemplatePlugin,CitationsPlugin - Automation/productivity:
SmartPastePlugin,SlashCommandsPlugin,BlocksLibraryPlugin,TranslationWorkflowPlugin - Manager-backed advanced plugins:
MediaManagerPlugin,DocumentManagerPlugin
- LLM Index: llms.txt
- LLM Full Guide: llms-full.txt
- Canonical Inventory: COMPONENT_INVENTORY.md
- Component Registry: components.json
- Registry Schema: components.schema.json
- Regenerate Registry:
npm run generate:components
npx @editora/cli add button
npx @editora/cli add modal
npx @editora/cli add datatable
npx @editora/cli add editor
npx @editora/cli add toast
npx @editora/cli add accordion
npx @editora/cli add ui-selectpackages/
βββ core/ # Framework-agnostic editor engine
βββ react/ # React integration layer
βββ plugins/ # 11 modular plugins
β βββ bold/ # Text formatting
β βββ italic/
β βββ heading/
β βββ paragraph/
β βββ history/ # Undo/redo
β βββ list/ # Bullet/numbered lists
β βββ blockquote/
β βββ table/ # Advanced tables
β βββ image/ # Upload & management
β βββ link/ # URL management
β βββ codeblock/ # Syntax highlighting
βββ themes/ # Theming system
βββ performance/ # Optimization utilities
Everything is a plugin - from basic formatting to advanced features. This ensures:
- Modularity: Easy to add/remove features
- Maintainability: Isolated concerns
- Extensibility: Custom plugins without core changes
- Performance: Lazy loading and tree shaking
- Transaction-Based: All changes are atomic
- Structural Sharing: Efficient memory usage
- Undo/Redo: Built-in history management
- Collaboration Ready: CRDT-compatible architecture
- AST-Based: Documents as JSON-serializable trees
- Type Safety: Runtime validation
- Extensibility: Custom node and mark types
- Serialization: HTML β JSON conversion
import { EditoraEditor } from '@editora/react';
import "@editora/themes/themes/default.css";
import {
BoldPlugin,
ItalicPlugin,
HeadingPlugin,
HistoryPlugin
} from '@editora/plugins';
function MyEditor() {
const [content, setContent] = useState('<p>Start writing...</p>');
return (
<EditoraEditor
value={content}
onChange={setContent}
plugins={[
BoldPlugin(),
ItalicPlugin(),
HeadingPlugin(),
HistoryPlugin()
]}
/>
);
}Editora includes a comprehensive status bar that displays real-time editing information.
function EditorWithStatusBar() {
return (
<EditoraEditor
statusbar={true}
plugins={[
BoldPlugin(),
ItalicPlugin(),
HeadingPlugin(),
HistoryPlugin()
]}
/>
);
}- Left Section: Cursor position (Ln X, Col Y) and selection information
- Right Section: Word count, character count, and line count
- Real-time Updates: Information updates as you type and move the cursor
- Selection Tracking: Shows selected character and word counts when text is selected
<editora-editor
statusbar="true"
plugins="bold italic underline history"
toolbar-items="bold italic underline | undo redo"
>
<p>Start editing to see status bar updates...</p>
</editora-editor>import { EditoraEditor } from '@editora/react';
import { MediaManagerPlugin, TablePlugin } from '@editora/plugins';
import { createPerformanceMonitor } from '@editora/performance';
const mediaPlugin = MediaManagerPlugin({
uploadUrl: '/api/upload',
maxSize: 5 * 1024 * 1024, // 5MB
allowedTypes: ['image/jpeg', 'image/png']
});
const tablePlugin = TablePlugin();
const monitor = createPerformanceMonitor();
function AdvancedEditor() {
return (
<EditoraEditor
plugins={[mediaPlugin, tablePlugin]}
onInit={(editor) => {
// Performance monitoring
monitor.startOperation('editor-init');
monitor.endOperation();
}}
/>
);
}Editora provides a framework-agnostic web component that works with any JavaScript framework or vanilla HTML.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Editora Web Component</title>
<script type="module" src="https://cdn.jsdelivr.net/npm/@editora/core/dist/webcomponent.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@editora/core/dist/webcomponent.min.css">
</head>
<body>
<editora-editor
plugins="bold italic underline history"
toolbar-items="bold italic underline | undo redo"
height="300"
>
<p>Start editing your content here...</p>
</editora-editor>
<script>
// Access the editor programmatically
const editor = document.querySelector('editora-editor');
// Get content
const content = editor.innerHTML;
// Set content
editor.innerHTML = '<p>New content</p>';
// Get API for advanced operations
const api = editor.getAPI();
if (api) {
console.log('Editor content:', api.getContent());
}
</script>
</body>
</html>plugins: Space-separated list of plugin names (e.g., "bold italic underline history")toolbar-items: Space-separated toolbar configuration with|for groupsheight: Editor height in pixelsplaceholder: Placeholder text when editor is empty
All 37+ native plugins are available: bold, italic, underline, strikethrough, link, table, list, history, heading, blockquote, code, textColor, backgroundColor, fontSize, fontFamily, textAlignment, indent, image, anchor, embedIframe, math, specialCharacters, emojis, a11yChecker, comments, fullscreen, and more.
import '@editora/themes'; // Base theme
import '@editora/themes/dark.css'; // Dark theme
import { setGlobalTheme } from '@editora/themes';
// Apply dark theme
setGlobalTheme('dark');import { defaultSanitizer, ContentValidator } from '@editora/core';
// Sanitize user input
const cleanContent = defaultSanitizer.sanitize(userInput);
// Validate content
const validation = ContentValidator.validateText(cleanContent);
if (!validation.valid) {
console.warn('Security warnings:', validation.warnings);
}import { Plugin } from '@editora/core';
const myCustomPlugin: Plugin = {
name: 'my-plugin',
nodes: {
highlight: {
attrs: { color: { default: 'yellow' } },
parseDOM: [{ tag: 'mark' }],
toDOM: (mark) => ['mark', { style: `background: ${mark.attrs.color}` }, 0]
}
},
commands: {
toggleHighlight: (state, dispatch) => {
// Implementation
return true;
}
},
toolbar: [{
id: 'highlight',
icon: 'ποΈ',
label: 'Highlight',
command: 'toggleHighlight'
}],
keybindings: {
'Mod-Shift-H': 'toggleHighlight'
}
};:root {
--rte-color-primary: #007bff;
--rte-color-text-primary: #212529;
--rte-font-family-base: 'Inter', sans-serif;
/* 30+ customizable variables */
}const imagePlugin = MediaManagerPlugin({
uploadUrl: '/api/upload',
maxSize: 10 * 1024 * 1024,
allowedTypes: ['image/jpeg', 'image/png', 'image/webp'],
uploadFunction: async (file) => {
// Custom upload logic
return await uploadToCloud(file);
}
});- Transaction Batching: Group multiple operations
- Debounced Updates: UI responsiveness optimization
- Memory Management: Automatic cleanup and monitoring
- Virtual Scrolling: Large document support
- Lazy Loading: Plugin loading on demand
import { createPerformanceMonitor } from '@editora/performance';
const monitor = createPerformanceMonitor();
// Track operations
monitor.startOperation('render');
// ... operation
const metrics = monitor.endOperation();
console.log('Render time:', metrics.renderTime, 'ms');
console.log('Memory usage:', metrics.memoryUsage, 'MB');- HTML Sanitization: Configurable tag/attribute filtering
- URL Validation: Protocol and domain checking
- File Upload Security: Size and type validation
- XSS Prevention: Content validation and filtering
- DoS Protection: Nesting and size limits
import { ContentValidator } from '@editora/core';
// Validate text content
const result = ContentValidator.validateText('<script>alert(1)</script>');
// result.valid = false, warnings include XSS detection
// Validate file uploads
const fileResult = ContentValidator.validateFile(file, {
maxSize: 5 * 1024 * 1024,
allowedTypes: ['image/jpeg', 'image/png']
});# Run all tests
npm test
# Run specific package tests
npm test -- packages/core
# Run with coverage
npm run test:coverageEditora also ships a production UI component system through @editora/ui-core and @editora/ui-react. The latest Gantt planning workspace includes task, summary, and milestone bars; dependency links; drag/resize editing; baselines; critical tasks; split segments; keyboard selection; links you draw by dragging; a two-level time header with weekend and holiday shading; scheduling that pushes later tasks and a computed critical path; in-place rename and task creation; translatable labels; SVG export and printing; bar design variants; and row virtualization for large plans.
- React package:
@editora/ui-react - Web Components package:
@editora/ui-core - Gantt demos: https://qjr47y-5173.csb.app/gantt and https://editora-ecosystem-storybook.netlify.app/?path=/story/ui-gantt--full-page-workspace
EditorState: Immutable editor state with transactionsSchema: Document structure definitionPlugin: Extensible plugin base classTransaction: Atomic state changes
EditoraEditor: Main editor componentToolbar: Configurable button groupsEditorContent: ContentEditable area
useEditor: Access editor state and dispatchuseCommand: Execute commands programmaticallyuseSelection: Track selection changes
# Clone repository
git clone https://github.com/ajaykr089/Editora.git
cd Editora
# Install dependencies
npm install
# Start development
npm run dev
# Build packages
npm run build
# Run tests
npm test- Create plugin package in
packages/plugins/ - Implement plugin class extending base
Plugin - Add schema extensions, commands, toolbar items
- Write tests and documentation
- Submit pull request
MIT License - see LICENSE file for details.
Built with modern web technologies:
- React 18 - UI framework
- TypeScript 5 - Type safety
- Rollup - Module bundling
- Jest - Testing framework
- Lerna - Monorepo task running
- Changesets - Versioning and publishing
Inspired by modern editor architecture and best practices.
- Documentation: Editora Ecosystem
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Rich Text Editor - Enterprise-grade editing for modern web applications.













