@editora/react
v1.0.17
Published
React components for Editora - Best Free Premium Rich Text Editor. Free React WYSIWYG editor with enterprise features, 30+ free plugins, and accessibility support.
Downloads
743
Maintainers
Keywords
Readme
@editora/react
[!IMPORTANT] Live Website: https://editora-ecosystem.netlify.app/
Storybook: https://editora-ecosystem-storybook.netlify.app/
React components for Editora Rich Text Editor - A modern, extensible WYSIWYG editor.
📦 Installation
npm install @editora/react @editora/core @editora/plugins @editora/themesRuntime Dependency Matrix
- Required:
@editora/react,@editora/core,react,react-dom - Optional but recommended:
@editora/plugins(toolbar/plugin features),@editora/themes(default/dark/acme CSS) - When using
@editora/plugins, also import@editora/plugins/styles.cssfor plugin UI surfaces (table toolbar, dialogs, pickers). - For plugin imports: use
@editora/plugins(full),@editora/plugins/lite(common),@editora/plugins/enterprise(advanced), or per-plugin subpaths like@editora/plugins/bold. - All plugin entry paths are free and fully customizable.
Minimal install:
npm install @editora/react @editora/core react react-domFull-featured install:
npm install @editora/react @editora/core @editora/plugins @editora/themes react react-dom🎯 Overview
The React package provides ready-to-use React components for building rich text editing experiences. It includes hooks, components, and utilities specifically designed for React applications.
✨ Features
- React Hooks: Modern hooks-based API (
useEditor,useEditorState) - TypeScript: Full type safety and IntelliSense support
- SSR Compatible: Works with Next.js and server-side rendering
- Tree Shakeable: Optimized bundle sizes
- Accessible: WCAG 2.1 compliant
- Multi-Instance: Support for multiple editors on one page
🚀 Quick Start
Basic Editor
import { EditoraEditor } from '@editora/react';
import { BoldPlugin, ItalicPlugin } from '@editora/plugins';
import "@editora/plugins/styles.css";
import "@editora/themes/themes/default.css";
function App() {
const [content, setContent] = useState('<p>Start writing...</p>');
return (
<EditoraEditor
value={content}
onChange={setContent}
plugins={[
BoldPlugin(),
ItalicPlugin()
]}
placeholder="Type something..."
/>
);
}Full-Featured Editor
import { EditoraEditor } from '@editora/react';
import {
BoldPlugin,
ItalicPlugin,
UnderlinePlugin,
HeadingPlugin,
ParagraphPlugin,
ListPlugin,
LinkPlugin,
MediaManagerPlugin,
TablePlugin,
CodeSamplePlugin,
HistoryPlugin
} from '@editora/plugins';
import "@editora/plugins/styles.css";
import "@editora/themes/themes/default.css";
function FullEditor() {
const [content, setContent] = useState('');
const plugins = [
BoldPlugin(),
ItalicPlugin(),
UnderlinePlugin(),
HeadingPlugin(),
ListPlugin(),
MediaManagerPlugin()
];
return (
<div className="editor-container">
<EditoraEditor
value={content}
onChange={setContent}
plugins={plugins}
placeholder="Start writing your document..."
autofocus
/>
</div>
);
}Performance + Accessibility Config
<EditoraEditor
plugins={[BoldPlugin(), ItalicPlugin()]}
accessibility={{
enableARIA: true,
keyboardNavigation: true,
checker: true, // auto-enables a11y checker if factory/plugin is available
}}
performance={{
debounceInputMs: 120,
viewportOnlyScan: true,
}}
/>Content Sizing (Scrollable vs Auto Height)
// Default: fixed layout + scrollable content area
<EditoraEditor plugins={[BoldPlugin()]} />
// Optional: grow editor content height with content
<EditoraEditor
plugins={[BoldPlugin()]}
content={{
autoHeight: true,
minHeight: 220,
maxHeight: 700, // optional cap; keeps scrolling after cap
}}
/>With Custom Toolbar
import { EditoraEditor, Toolbar, ToolbarButton } from '@editora/react';
import { useEditor } from '@editora/react/hooks';
function EditorWithCustomToolbar() {
const { editor, html, setHtml } = useEditor({
plugins: [/* your plugins */],
content: '<p>Hello</p>'
});
return (
<div>
<Toolbar editor={editor}>
<ToolbarButton command="bold" icon="bold" />
<ToolbarButton command="italic" icon="italic" />
<ToolbarButton command="underline" icon="underline" />
<div className="separator" />
<ToolbarButton command="heading" level={1} icon="h1" />
<ToolbarButton command="heading" level={2} icon="h2" />
</Toolbar>
<div
ref={(el) => el && editor.mount(el)}
className="editor-content"
/>
</div>
);
}📖 API Reference
Components
<EditoraEditor />
Main editor component with built-in toolbar.
Props:
interface EditoraEditorProps {
// Content
value?: string;
defaultValue?: string;
onChange?: (html: string) => void;
// Plugins
plugins?: Plugin[];
// Configuration
placeholder?: string;
readonly?: boolean;
autofocus?: boolean;
maxLength?: number;
// Styling
className?: string;
style?: React.CSSProperties;
// Toolbar
showToolbar?: boolean;
toolbarItems?: ToolbarItem[];
toolbarPosition?: 'top' | 'bottom' | 'floating';
// Events
onFocus?: () => void;
onBlur?: () => void;
onReady?: (editor: Editor) => void;
}<Toolbar />
Customizable toolbar component.
Props:
interface ToolbarProps {
editor: Editor;
items?: ToolbarItem[];
position?: 'top' | 'bottom' | 'floating';
className?: string;
}<ToolbarButton />
Individual toolbar button.
Props:
interface ToolbarButtonProps {
command: string;
icon?: React.ReactNode;
label?: string;
active?: boolean;
disabled?: boolean;
onClick?: () => void;
}Hooks
useEditor(config)
Main hook for editor management.
const { editor, html, json, setHtml, setJson } = useEditor({
plugins: [...],
content: '<p>Initial content</p>',
onChange: (html) => console.log(html)
});Returns:
editor: Editor instancehtml: Current HTML contentjson: Current JSON contentsetHtml: Function to set HTML contentsetJson: Function to set JSON content
useEditorState(editor)
Hook for accessing editor state.
const {
isFocused,
isEmpty,
canUndo,
canRedo
} = useEditorState(editor);useEditorCommands(editor)
Hook for editor commands.
const {
bold,
italic,
undo,
redo,
insertText,
insertImage
} = useEditorCommands(editor);🎨 Theming
Using Built-in Themes
import "@editora/themes/themes/default.css";
import "@editora/themes/themes/dark.css";
import "@editora/themes/themes/acme.css";
<div data-theme="dark">
<EditoraEditor />
</div>Custom Theme
:is([data-theme="custom-brand"], .editora-theme-custom-brand) {
--rte-color-primary: #2563eb;
--rte-color-primary-hover: #1d4ed8;
--rte-color-text-primary: #0f172a;
--rte-color-bg-primary: #ffffff;
--rte-color-border: #cbd5e1;
}
[data-theme="dark"] {
--rte-color-primary: #58a6ff;
}Apply it in React with a wrapper:
<div data-theme="custom-brand">
<EditoraEditor />
</div>🔌 Plugin Configuration
Bold Plugin
import { BoldPlugin } from '@editora/plugins';
const boldPlugin = BoldPlugin({
keyboard: 'Mod-b',
icon: <BoldIcon />
});Image Plugin with Upload
import { MediaManagerPlugin } from '@editora/plugins';
const imagePlugin = MediaManagerPlugin({
upload: async (file) => {
const url = await uploadToServer(file);
return url;
},
validate: (file) => {
return file.size < 5 * 1024 * 1024; // 5MB limit
},
resize: true,
maxWidth: 1200
});Link Plugin
import { LinkPlugin } from '@editora/plugins';
const linkPlugin = LinkPlugin({
openOnClick: false,
validate: (url) => {
return url.startsWith('http') || url.startsWith('https');
},
onLinkClick: (url) => {
window.open(url, '_blank', 'noopener,noreferrer');
}
});💡 Examples
Form Integration
function BlogPostForm() {
const [formData, setFormData] = useState({
title: '',
content: ''
});
const handleSubmit = async (e) => {
e.preventDefault();
await fetch('/api/posts', {
method: 'POST',
body: JSON.stringify(formData)
});
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={formData.title}
onChange={(e) => setFormData({ ...formData, title: e.target.value })}
placeholder="Post title"
/>
<EditoraEditor
value={formData.content}
onChange={(content) => setFormData({ ...formData, content })}
plugins={[/* ... */]}
/>
<button type="submit">Publish</button>
</form>
);
}Controlled Editor with Save
function DocumentEditor() {
const [content, setContent] = useState('');
const [isSaving, setIsSaving] = useState(false);
const handleSave = async () => {
setIsSaving(true);
try {
await fetch('/api/save', {
method: 'POST',
body: JSON.stringify({ content })
});
alert('Saved successfully!');
} catch (error) {
alert('Failed to save');
} finally {
setIsSaving(false);
}
};
return (
<div>
<div className="toolbar-actions">
<button onClick={handleSave} disabled={isSaving}>
{isSaving ? 'Saving...' : 'Save'}
</button>
</div>
<EditoraEditor
value={content}
onChange={setContent}
plugins={[/* ... */]}
/>
</div>
);
}Read-Only Mode
function ArticlePreview({ html }) {
return (
<EditoraEditor
value={html}
readonly
showToolbar={false}
className="article-preview"
/>
);
}🔧 TypeScript Support
The package is written in TypeScript and includes comprehensive type definitions.
import type {
Editor,
Plugin,
ToolbarItem,
EditorConfig
} from '@editora/react';
const config: EditorConfig = {
plugins: [],
onChange: (html: string) => {
// TypeScript knows html is a string
}
};📱 Responsive Design
The editor automatically adapts to different screen sizes:
<EditoraEditor
// Toolbar collapses to hamburger menu on mobile
toolbarBreakpoint={768}
// Custom mobile configuration
mobileConfig={{
toolbarPosition: 'bottom',
compactMode: true
}}
/>♿ Accessibility
The editor is fully accessible and follows WCAG 2.1 guidelines:
- Keyboard navigation support
- Screen reader announcements
- ARIA attributes
- Focus management
- High contrast mode support
📄 License
MIT © Ajay Kumar
