
Syncfusion React Rich Text Editor
- 480 installs
- 3 repo stars
- Updated July 28, 2026
- syncfusion/react-ui-components-skills
syncfusion-react-rich-text-editor is a Claude Code skill that helps developers integrate Syncfusion's React Rich Text Editor component into React applications needing WYSIWYG editing.
About
syncfusion-react-rich-text-editor is a Syncfusion agent skill from react-ui-components-skills for wiring Syncfusion's React Rich Text Editor into React apps. The skill targets developers adding formatted text editing, toolbar configuration, and editor lifecycle handling in SaaS dashboards, CMS admin panels, and internal tools. It fits when you need a production-grade RTE instead of building custom contenteditable logic from scratch. Source material is sparse in the catalog entry, so pair it with Syncfusion React documentation for API specifics, licensing, and bundle configuration.
- syncfusion-react-rich-text-editor
Syncfusion React Rich Text Editor by the numbers
- 480 all-time installs (skills.sh)
- +56 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #862 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/syncfusion/react-ui-components-skills --skill syncfusion-react-rich-text-editorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 480 |
|---|---|
| repo stars | ★ 3 |
| Last updated | July 28, 2026 |
| Repository | syncfusion/react-ui-components-skills ↗ |
How do you add a Syncfusion rich text editor in React?
Use syncfusion-react-rich-text-editor for development tasks
Who is it for?
React developers standardizing on Syncfusion UI who need guided RTE setup during feature work.
Skip if: Teams not using Syncfusion React or projects that only need a lightweight markdown textarea without a WYSIWYG dependency.
When should I use this skill?
User asks to add, configure, or debug Syncfusion React Rich Text Editor in a React codebase.
What you get
React components with configured Syncfusion Rich Text Editor instances, toolbar options, and content binding patterns.
- Rich Text Editor component integration
- Toolbar and binding configuration
Files
Syncfusion React Rich Text Editor
A WYSIWYG (What You See Is What You Get) editor for creating and formatting rich content as HTML or Markdown. Supports toolbars, media insertion, AI assistance, smart editing features, form validation, and deep customization.
When to Use This Skill
- Setting up a rich text / WYSIWYG editor in a React app
- Configuring toolbar items, types, or positions
- Switching between HTML and Markdown editor modes
- Inserting images, video, audio, or files
- Working with smart editing features: emoji, slash menu, mentions, mail merge
- Integrating AI assistant into the editor
- Handling editor value: get, set, two-way binding, auto-save, import/export
- Applying paste cleanup, form validation, or read-only mode
- Customizing styles, accessibility, or keyboard shortcuts
Quick Start
npm install @syncfusion/ej2-react-richtexteditor// src/App.css - add CSS imports
// @import '../node_modules/@syncfusion/ej2-base/styles/tailwind3.css';
// @import '../node_modules/@syncfusion/ej2-buttons/styles/tailwind3.css';
// @import '../node_modules/@syncfusion/ej2-inputs/styles/tailwind3.css';
// @import '../node_modules/@syncfusion/ej2-lists/styles/tailwind3.css';
// @import '../node_modules/@syncfusion/ej2-navigations/styles/tailwind3.css';
// @import '../node_modules/@syncfusion/ej2-popups/styles/tailwind3.css';
// @import '../node_modules/@syncfusion/ej2-splitbuttons/styles/tailwind3.css';
// @import '../node_modules/@syncfusion/ej2-richtexteditor/styles/tailwind3.css';
import {
HtmlEditor, Image, Inject, Link,
QuickToolbar, RichTextEditorComponent, Toolbar
} from '@syncfusion/ej2-react-richtexteditor';
function App() {
return (
<RichTextEditorComponent height={450}>
<Inject services={[Toolbar, Image, Link, HtmlEditor, QuickToolbar]} />
</RichTextEditorComponent>
);
}
export default App;Module Injection Reference
Inject only the modules your app needs — this keeps the bundle lean.
| Module | What it enables |
|---|---|
Toolbar | Toolbar rendering and commands |
HtmlEditor | HTML editing mode (default) |
MarkdownEditor | Markdown editing mode |
Link | Hyperlink insert/edit/remove |
Image | Image insertion and management |
Video | Video insertion |
Audio | Audio insertion |
Table | HTML table insert/edit |
QuickToolbar | Floating toolbar for images/links |
PasteCleanup | Clean up pasted content formatting |
ClipboardCleanup | Clean clipboard on copy/cut |
FileManager | File browser for server-side images |
Resize | Resizable editor area |
Count | Character count display |
EmojiPicker | Emoji search and insert |
SlashMenu | Slash / command menu |
ImportExport | Import Word, export Word/PDF |
CodeBlock | Inline code block formatting |
AutoFormat | Auto-convert Markdown syntax while typing |
FormatPainter | Copy-paste text formatting |
AIAssistant | AI assistant integration |
Navigation Guide
Getting Started
📄 Read: references/getting-started.md
- Installation, npm setup, CSS imports
- Basic component implementation
- Module injection patterns
- Toolbar configuration basics
- Running the application
Editor Modes
📄 Read: references/editor-modes.md
- HTML editor mode (default WYSIWYG)
- Markdown editor mode with preview
- IFrame vs DIV mode
- Inline editing
- Resizable editor
Toolbar Configuration
📄 Read: references/toolbar-configuration.md
- Default toolbar items
- Toolbar types: Expand, MultiRow, Scrollable
- Toolbar position (top/bottom)
- Sticky/floating toolbar
- Quick toolbar for images and links
Toolbar Tools
📄 Read: references/toolbar-tools.md
- Built-in tools reference (Bold, Italic, Formats, etc.)
- Custom toolbar items with templates
- Text formatting tools
- Styling tools (font, color, alignment)
- Fullscreen tool
Inserting Media
📄 Read: references/insert-media.md
- Inserting images (URL, upload, base64)
- Video insertion and configuration
- Audio insertion
- File browser integration
Inserting Content
📄 Read: references/insert-content.md
- Tables: insert, resize, merge cells
- Hyperlinks: create, edit, open in new tab
- Code blocks
- Custom format blocks
Smart Editing Features
📄 Read: references/smart-editing.md
- Emoji picker
- Slash menu (type
/to open) - Mentions (tag users)
- Mail merge
Managing Editor Value
📄 Read: references/editor-value.md
- Setting initial value
- Getting value via property, event, or method
- Two-way binding with React state
- Auto-save with
saveInterval - Import/export Word and PDF
- Markdown preview
- Character count and maxLength
- Source code view
Paste & Clipboard
📄 Read: references/paste-clipboard.md
- Paste cleanup configuration
- Clipboard cleanup on copy/cut
- Executing editor commands programmatically
Validation & Security
📄 Read: references/validation-security.md
- Form support and submission
- XHTML validation
- Read-only mode
- XSS prevention
AI Assistant
📄 Read: references/ai-assistant.md
- AI integration setup
- AI assistant properties
- Customizing AI toolbar and responses
Accessibility & Globalization
📄 Read: references/accessibility.md
- WCAG 2.1 compliance
- Keyboard shortcuts
- Globalization, localization, RTL
- Style encapsulation
Styling & Customization
📄 Read: references/styling-customization.md
- CSS variable customization
- Style encapsulation (shadow DOM)
- Third-party integrations (CodeMirror, Mention library)
- Spell/grammar check
Undo / Redo
📄 Read: references/undo-redo.md
- Undo/redo manager behavior
- Keyboard shortcuts
- Programmatic undo/redo
Enter Key & Selection
📄 Read: references/enter-key-selection.md
- Enter key configuration (P, BR, DIV)
- Selection API
- Cursor positioning
Events
📄 Read: references/events.md
- Infer EventArgs Type value for each events
- Lifecycle events:
created,destroyed,focus,blur - Content change:
changeevent withChangeEventArgs - Action events:
actionBegin(cancelable),actionComplete - Toolbar events:
toolbarClick,updatedToolbarStatus - Dialog & popup events:
beforeDialogOpen/Close,beforePopupOpen/Close - Media & file events: image/audio/video upload, select, remove, drop
- Paste & clipboard events:
beforePasteCleanup,afterPasteCleanup - AI Assistant events:
aiAssistantPromptRequest,aiAssistantToolbarClick - Resize, slash menu, selection, quick toolbar, import/export events
Methods
📄 Read: references/methods.md
- Focus & content:
focusIn,focusOut,getHtml,getText,getSelectedHtml - Toolbar:
enableToolbarItem,disableToolbarItem,removeToolbarItem - Dialog:
showDialog,closeDialogwithDialogTypeenum - Selection:
selectAll,getRange,selectRange - Undo/redo:
clearUndoRedo - AI Assistant:
executeAIPrompt,addAIPromptResponse,getAIPromptHistory,clearAIPromptHistory - Utility:
executeCommand(allCommandNamevalues),sanitizeHtml,destroy
Properties Reference
📄 Read: references/properties.md
- Core:
height,width,enabled,readonly,placeholder,cssClass - Toolbar:
toolbarSettings,quickToolbarSettings,floatingToolbarOffset - Editor mode & behavior:
editorMode,iframeSettings,inlineMode,enterKey - Value & content:
value,maxLength,showCharCount,saveInterval,enableHtmlSanitizer - Media:
insertImageSettings,insertVideoSettings,insertAudioSettings,fileManagerSettings - Font, color & format:
fontFamily,fontSize,fontColor,backgroundColor,format,codeBlockSettings - Paste:
pasteCleanupSettings,enableClipboardCleanup - AI Assistant:
aiAssistantSettings(full configuration reference) - Import/export:
importWord,exportWord,exportPdf - Misc:
undoRedoSteps,keyConfig,slashMenuSettings,emojiPickerSettings
How-To Guides
📄 Read: references/how-to.md
- Capture Ctrl keys to update value
- Change default font family
- Check uploaded image size
- Customize placeholder style
- Customize shortcut keys
- File attachment
- Format code blocks
- Position cursor at end of content
- Rename images on server
- RTE inside Dialog or Tab
- Set cursor at specific range
- Tailwind preflight fix
- Update value programmatically
Common Patterns
Read value on change
import { ChangeEventArgs } from '@syncfusion/ej2-react-richtexteditor';
function App() {
const onChange = (args: ChangeEventArgs) => {
console.log(args.value); // HTML string
};
return (
<RichTextEditorComponent change={onChange}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>
);
}Controlled value with React state
const [content, setContent] = useState('<p>Hello</p>');
<RichTextEditorComponent value={content} change={(e) => setContent(e.value)}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>Markdown mode
import { MarkdownEditor } from '@syncfusion/ej2-react-richtexteditor';
<RichTextEditorComponent editorMode="Markdown">
<Inject services={[Toolbar, MarkdownEditor]} />
</RichTextEditorComponent>Accessibility & Globalization in Syncfusion React Rich Text Editor
Table of Contents
WCAG Compliance
The Syncfusion RTE follows WAI-ARIA 1.2 and WCAG 2.1 Level AA accessibility standards:
- Proper ARIA roles (
role="textbox",aria-label,aria-multiline) - Focus management: keyboard users can navigate the toolbar and editor content
- Color contrast ratios meet WCAG AA requirements in all built-in themes
- Screen reader compatible — tested with NVDA, JAWS, and VoiceOver
No additional configuration is required for basic WCAG compliance.
Keyboard Support
The RTE provides comprehensive keyboard shortcuts for formatting and navigation.
Content Formatting Shortcuts
| Shortcut | Action |
|---|---|
Ctrl + B | Toggle bold |
Ctrl + I | Toggle italic |
Ctrl + U | Toggle underline |
Ctrl + Shift + S | Toggle strikethrough |
Ctrl + \ | Clear formatting |
Ctrl + L | Align left |
Ctrl + E | Align center |
Ctrl + R | Align right |
Ctrl + J | Justify |
Editor Navigation
| Shortcut | Action |
|---|---|
Ctrl + Z | Undo |
Ctrl + Y | Redo |
Ctrl + A | Select all |
Ctrl + K | Insert/edit hyperlink |
F10 | Focus toolbar |
Escape | Exit toolbar focus, return to content |
Tab | Move to next toolbar item |
Shift + Tab | Move to previous toolbar item |
Customizing Keyboard Shortcuts
Override default shortcuts or add new ones via formatter:
import { IHtmlFormatterModel } from '@syncfusion/ej2-react-richtexteditor';
const customShortcut = {
keyConfig: {
bold: 'ctrl+alt+b', // override Bold shortcut
italic: 'ctrl+alt+i', // override Italic shortcut
}
};
<RichTextEditorComponent formatter={customShortcut}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>Globalization and Localization
Localization (translating UI strings)
Load locale strings to translate toolbar tooltips, dialog labels, and messages:
import { L10n } from '@syncfusion/ej2-base';
L10n.load({
'de': {
'richtexteditor': {
'alignments': 'Ausrichtungen',
'justifyLeft': 'Links ausrichten',
'justifyCenter': 'Mitte',
'justifyRight': 'Rechts ausrichten',
'justifyFull': 'Rechtfertigen',
'fontName': 'Schriftart Name',
'fontSize': 'Schriftgröße',
// ... other strings
}
}
});
<RichTextEditorComponent locale="de">
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>Number and Date Formatting
For number/date formatting within the editor content, use Syncfusion's Internationalization utility:
import { Internationalization } from '@syncfusion/ej2-base';
const intl = new Internationalization();
const formattedDate = intl.formatDate(new Date(), { skeleton: 'yMd', locale: 'fr' });RTL Support
Enable right-to-left text direction for Arabic, Hebrew, or other RTL languages:
<RichTextEditorComponent enableRtl={true} locale="ar">
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>RTL mode flips:
- Toolbar item ordering (right to left)
- Text direction in the editor content area
- Dialog and popup positions
RTL for the whole app — set it globally:
import { enableRtl } from '@syncfusion/ej2-base';
enableRtl(true);Style Encapsulation
Style encapsulation prevents the host page's CSS from affecting editor content and prevents editor styles from leaking out. Uses ShadowDOM internally.
<RichTextEditorComponent enableHtmlSanitizer={true}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>For IFrame mode, content isolation is automatic since the editor renders in its own <iframe> document. See editor-modes.md for IFrame configuration.
When style conflicts occur:
- Use IFrame mode (
iframeSettings.enable: true) for strongest isolation - Add
e-rte-contentclass to your output container when rendering retrieved HTML outside the editor — this applies the correct content styles (seeeditor-value.mdfor the required CSS)
AI Assistant in Syncfusion React Rich Text Editor
Table of Contents
- Overview
- Integrating the AI Assistant
- AI Commands and Prompts
- Handling Responses
- Customizing the AI Toolbar
- Popup Dimensions
- Using Public Methods
Overview
The AI Assistant in the Rich Text Editor provides integrated AI capabilities for simplified content creation, editing, and enhancement. It includes an AssistView presented inside a pop-up interface, a dropdown of predefined prompts, and dedicated toolbar options for initiating AI interactions.
Integrating the AI Assistant
To enable the AI Assistant:
1. Add the AIAssistant service to the Inject array 2. Include AICommands and AIQuery in the toolbarSettings.items property 3. Configure the aiAssistantSettings with your AI backend endpoint
Installation
npm install @syncfusion/ej2-react-richtexteditorImporting Styles
The Rich Text Editor AI Assistant requires additional style references for proper rendering. Add the following to your src/App.css:
@import '../node_modules/@syncfusion/ej2-base/styles/tailwind3.css';
@import '../node_modules/@syncfusion/ej2-buttons/styles/tailwind3.css';
@import '../node_modules/@syncfusion/ej2-inputs/styles/tailwind3.css';
@import '../node_modules/@syncfusion/ej2-lists/styles/tailwind3.css';
@import '../node_modules/@syncfusion/ej2-navigations/styles/tailwind3.css';
@import '../node_modules/@syncfusion/ej2-popups/styles/tailwind3.css';
@import '../node_modules/@syncfusion/ej2-splitbuttons/styles/tailwind3.css';
@import '../node_modules/@syncfusion/ej2-richtexteditor/styles/tailwind3.css';
/* Required for AI Assistant */
@import '../node_modules/@syncfusion/ej2-interactive-chat/styles/tailwind3.css';
@import '../node_modules/@syncfusion/ej2-notifications/styles/tailwind3.css';Basic Setup with Functional Component
import { HtmlEditor, Image, Inject, Link, QuickToolbar, RichTextEditorComponent, Toolbar, AIAssistant, AIAssistantSettingsModel, ToolbarSettingsModel } from '@syncfusion/ej2-react-richtexteditor';
import * as React from 'react';
function App() {
const editor = React.createRef<RichTextEditorComponent>();
const toolbarSettings: ToolbarSettingsModel = { items: ['AICommands', 'AIQuery'] };
const aiAssistantSettings: AIAssistantSettingsModel = {
popupWidth: '600px',
popupMaxHeight: '400px'
};
return (
<RichTextEditorComponent
ref={editor}
toolbarSettings={toolbarSettings}
aiAssistantSettings={aiAssistantSettings}
>
<Inject services={[Toolbar, Image, Link, HtmlEditor, QuickToolbar, AIAssistant]} />
</RichTextEditorComponent>
);
}
export default App;AI Commands and Prompts
The AICommands toolbar item opens a menu containing predefined prompts. You can customize the commands and add preloaded prompts and suggestions using the aiAssistantSettings.
Adding Custom Commands
function App() {
const toolbarSettings: ToolbarSettingsModel = { items: ['AICommands', 'AIQuery'] };
const aiAssistantSettings: AIAssistantSettingsModel = {
commands: [
{ text: 'Rewrite', prompt: 'Rewrite the content to be more refined.' },
{ text: 'Elaborate', prompt: 'Expand on the following content with more detail and explanation:' },
{
text: 'Change Tone',
items: [
{ text: 'Professional', prompt: 'Rewrite the following content in a professional tone:' },
{ text: 'Casual', prompt: 'Rewrite the following content in a casual, conversational tone:' },
{ text: 'Direct', prompt: 'Rewrite the following content to be more direct and to the point:' },
],
},
]
};
return (
<RichTextEditorComponent toolbarSettings={toolbarSettings} aiAssistantSettings={aiAssistantSettings}>
<Inject services={[Toolbar, Image, Link, HtmlEditor, QuickToolbar, AIAssistant]} />
</RichTextEditorComponent>
);
}Preloading Prompts and Suggestions
const aiAssistantSettings: AIAssistantSettingsModel = {
prompts: [
{
prompt: 'What is Essential Studio?',
response: 'Essential Studio is a software toolkit by Syncfusion that offers a variety of UI controls, frameworks, and libraries for developing applications on web, desktop, and mobile platforms.'
}
],
suggestions: [
'What are the popular components of Essential Studio?',
'Which web frameworks are supported by Essential Studio?'
]
};Handling Responses
Security Warning
The Rich Text Editor does not handle or send requests to AI provider endpoints. All AI interactions must be processed at the application layer (preferably in the backend).
Ensure that:
- AI inputs are validated and moderated on the backend.
- API keys and secrets are never exposed in request bodies or client-side code.
- All requests to AI services are securely routed and managed through backend systems.
Executing a prompt triggers the aiAssistantPromptRequest event. You can handle streaming or non-streaming responses using the addAIPromptResponse method.
Handling Streaming Responses
const onPromptRequest = async (args: AIAssistantPromptRequestArgs) => {
const response = await fetch('/api/ai/stream', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ message: args.prompt + args.text }),
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error);
}
const stream = response.body.pipeThrough(new TextDecoderStream());
let fullText = '';
for await (const chunk of stream as unknown as AsyncIterable<string>) {
fullText += chunk;
editor.current?.addAIPromptResponse(fullText, false);
}
editor.current?.addAIPromptResponse(fullText, true);
};Handling Non-Streaming Responses
const onPromptRequest = async (args: AIAssistantPromptRequestArgs) => {
const response = await fetch('/api/ai/query', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ message: args.prompt + args.text }),
});
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const data = await response.text();
editor.current?.addAIPromptResponse(data, true);
};Customizing the AI Toolbar
Configure the toolbar items displayed in the Header, Prompt, and Response sections using the toolbar settings properties.
Available Toolbar Items
| Toolbar | Items |
|---|---|
| Header | AIcommands – Opens AI command options<br>Close – Closes the AI Assistant popup<br>Clear – Clear conversations |
| Prompt | Edit – Modify the prompt text<br>Copy – Copy prompt to clipboard |
| Response | Regenerate – Produce new response<br>Copy – Copy AI response<br>`\ |
Customizing Toolbar Configuration
const aiAssistantSettings: AIAssistantSettingsModel = {
headerToolbarSettings: ['AIcommands', 'Clear', 'Close'],
promptToolbarSettings: ['Edit', 'Copy'],
responseToolbarSettings: ['Regenerate', 'Copy', '|', 'Insert'],
prompts: [
{
prompt: 'What is Essential Studio?',
response: 'Essential Studio is a software toolkit by Syncfusion...'
}
]
};
<RichTextEditorComponent aiAssistantSettings={aiAssistantSettings}>
<Inject services={[Toolbar, Image, Link, HtmlEditor, QuickToolbar, AIAssistant]} />
</RichTextEditorComponent>Popup Dimensions
Customize the width and maximum height of the AI Assistant popup to fit your editor layout.
const aiAssistantSettings: AIAssistantSettingsModel = {
popupWidth: '600px', // or use numbers for pixels: 600
popupMaxHeight: '500px' // or use numbers for pixels: 500
};
<RichTextEditorComponent aiAssistantSettings={aiAssistantSettings}>
<Inject services={[Toolbar, Image, Link, HtmlEditor, QuickToolbar, AIAssistant]} />
</RichTextEditorComponent>Using Public Methods
Manage the AI Assistant programmatically using public methods.
Available Methods
| Method | Description |
|---|---|
getAIPromptHistory() | Get conversation history |
executeAIPrompt(prompt: string) | Send a prompt to the AI Assistant |
addAIPromptResponse(response: string, isFinalUpdate?: boolean) | Add response to AI Assistant |
showAIAssistantPopup() | Show the AI Assistant popup |
hideAIAssistantPopup() | Hide the AI Assistant popup |
clearAIPromptHistory() | Clear all conversation history |
Proofread Use Case Example
function App() {
const editor = React.createRef<RichTextEditorComponent>();
const toolbarSettings = { items: ['AICommands', 'AIQuery'] };
const onPromptRequest = () => {
setTimeout(() => {
const aiResponse = 'Dear Valued Customer, We are writing to inform you that there has been a recent change to our policies...';
editor.current?.addAIPromptResponse(aiResponse, false);
editor.current?.addAIPromptResponse(aiResponse, true);
}, 300);
};
const reviewContent = () => {
editor.current?.showAIAssistantPopup();
editor.current?.executeAIPrompt('Proof read the editor content.');
};
return (
<div>
<RichTextEditorComponent
ref={editor}
toolbarSettings={toolbarSettings}
aiAssistantPromptRequest={onPromptRequest}
>
<p>Your content here...</p>
<Inject services={[Toolbar, Image, Link, HtmlEditor, QuickToolbar, AIAssistant]} />
</RichTextEditorComponent>
<br />
<button className="e-btn e-primary" onClick={reviewContent}>
<span className="e-icons e-btn-icon e-check-large"></span>Proof read
</button>
</div>
);
}
export default App;Saving Conversation History
const onSaveBtnClick = () => {
const promptHistory = editor.current?.getAIPromptHistory();
console.log(promptHistory);
// Handle DB Post and save history to the DB
};
<button className="e-btn e-primary" onClick={onSaveBtnClick}>
<span className="e-icons e-save"></span>Save
</button>Editor Modes in Syncfusion React Rich Text Editor
Table of Contents
HTML Editor Mode
The default mode. The editor operates as a WYSIWYG HTML editor — the user sees formatted output while the component returns valid HTML markup. Inject HtmlEditor to enable it.
import { HtmlEditor, Image, Inject, Link, QuickToolbar, RichTextEditorComponent, Toolbar } from '@syncfusion/ej2-react-richtexteditor';
function App() {
const content = '<p>Edit <b>rich text</b> as HTML.</p>';
return (
<RichTextEditorComponent height={450} value={content}>
<Inject services={[Toolbar, Image, Link, HtmlEditor, QuickToolbar]} />
</RichTextEditorComponent>
);
}TheeditorModeprop defaults to'HTML'. You only need to set it explicitly when switching away from HTML.
IFrame vs DIV Mode
By default the editor renders in a <div> (DIV mode). Use iframeSettings.enable: true to isolate the editor content inside an <iframe> — this prevents parent page styles from leaking into the editor content area.
const iframeSettings: IFrameSettingsModel = { enable: true };
<RichTextEditorComponent iframeSettings={iframeSettings}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>When to use IFrame mode:
- Your page has global CSS that interferes with editor content styling
- You need strict style isolation between the editor and the host page
- Embedding the editor inside complex layout systems
Markdown Editor Mode
Set editorMode="Markdown" and inject MarkdownEditor. The editor operates on raw Markdown text. Use a third-party library like marked to render the Markdown as HTML for preview.
npm install markedimport { MarkdownEditor, Image, Inject, Link, RichTextEditorComponent, Toolbar } from '@syncfusion/ej2-react-richtexteditor';
import { marked } from 'marked';
import { useRef, useEffect } from 'react';
function App() {
const rteRef = useRef<RichTextEditorComponent>(null);
const initialValue = '**Bold text** and *italic text*\n\n- List item 1\n- List item 2';
const toolbarSettings: ToolbarSettingsModel = {
items: [
'Bold', 'Italic', 'StrikeThrough', '|',
'Formats', 'OrderedList', 'UnorderedList', '|',
'CreateLink', 'Image', '|', 'Undo', 'Redo'
]
};
return (
<RichTextEditorComponent
ref={rteRef}
editorMode="Markdown"
value={initialValue}
toolbarSettings={toolbarSettings}
height={400}
>
<Inject services={[Toolbar, MarkdownEditor, Image, Link]} />
</RichTextEditorComponent>
);
}Markdown Preview
To show a live HTML preview alongside the editor, listen to keyup on the textarea and render the Markdown:
function rendereComplete() {
const textArea = (rteRef.current as any).contentModule.getEditPanel() as HTMLTextAreaElement;
textArea.addEventListener('keyup', () => {
// render into your preview div
previewRef.current.innerHTML = marked(textArea.value);
});
}
<RichTextEditorComponent editorMode="Markdown" created={rendereComplete}>
<Inject services={[Toolbar, MarkdownEditor]} />
</RichTextEditorComponent>Supported Markdown Tags and Syntax
Block-level: h1–h6, blockquote, pre, p, ol, ul Inline: Bold, Italic, StrikeThrough, InlineCode, SubScript, SuperScript, UpperCase, LowerCase
Inline Editing
Inline editing turns any existing HTML element into an editable RTE without a visible border or toolbar until the user clicks into it. Useful for in-place editing in cards, lists, or dashboards.
<RichTextEditorComponent inlineMode={{ enable: true, onSelection: true }}>
<Inject services={[HtmlEditor, QuickToolbar]} />
</RichTextEditorComponent>onSelection: true— toolbar appears only when user selects textonSelection: false— toolbar appears on focus
Resizable Editor
Inject Resize to let users drag-resize the editor's height at runtime.
import { Resize } from '@syncfusion/ej2-react-richtexteditor';
<RichTextEditorComponent enableResize={true}>
<Inject services={[Toolbar, HtmlEditor, Resize]} />
</RichTextEditorComponent>You can also set min/max dimensions:
<RichTextEditorComponent
enableResize={true}
minHeight="200px"
maxHeight="600px"
>
<Inject services={[Toolbar, HtmlEditor, Resize]} />
</RichTextEditorComponent>Managing Editor Value in Syncfusion React Rich Text Editor
Table of Contents
- Setting Initial Value
- Getting Value
- Two-Way Binding
- Auto-Save
- Character Count and Max Length
- Source Code View
- Import and Export
- Markdown Preview
- Placeholder Text
- Encoded HTML Value
Setting Initial Value
// Direct HTML string via value prop
<RichTextEditorComponent value="<p>Hello <b>World</b></p>">
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>Via ref after mount (useful when value comes from an async source):
const rteRef = useRef<RichTextEditorComponent>(null);
useEffect(() => {
if (rteRef.current) {
rteRef.current.value = fetchedContent;
}
}, [fetchedContent]);
<RichTextEditorComponent ref={rteRef}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>Getting Value
Via change event (most common)
Fires when the editor loses focus and content has changed:
import { ChangeEventArgs } from '@syncfusion/ej2-react-richtexteditor';
const onChange = (args: ChangeEventArgs) => {
console.log(args.value); // HTML string
};
<RichTextEditorComponent change={onChange}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>Via ref property
const content = rteRef.current?.value;Via public methods
const htmlContent = rteRef.current?.getHtml(); // returns HTML string
const textContent = rteRef.current?.getText(); // returns plain text (no HTML tags)Two-Way Binding
Use React useState — pass state as value and update state in change:
function App() {
const [content, setContent] = useState('<p>Initial content</p>');
return (
<RichTextEditorComponent
value={content}
change={(e: ChangeEventArgs) => setContent(e.value)}
>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>
);
}When state is shared, multiple editor instances stay in sync automatically:
function App() {
const [content, setContent] = useState('Initial content');
return (
<>
<RichTextEditorComponent value={content} change={(e) => setContent(e.value)}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>
<RichTextEditorComponent value={content}>
<Inject services={[HtmlEditor]} />
</RichTextEditorComponent>
</>
);
}Auto-Save
Set saveInterval (milliseconds) to trigger the change event automatically during idle periods — great for drafting without relying on the user to tab out.
const onAutoSave = (e: ChangeEventArgs) => {
localStorage.setItem('draft', e.value);
};
<RichTextEditorComponent saveInterval={2000} change={onAutoSave}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>Character Count and Max Length
Inject Count, set showCharCount={true}. Use maxLength to cap content length.
import { Count } from '@syncfusion/ej2-react-richtexteditor';
<RichTextEditorComponent showCharCount={true} maxLength={500}>
<Inject services={[Toolbar, HtmlEditor, Count]} />
</RichTextEditorComponent>Character count color indicators:
- Black — below 70% of
maxLength - Orange — 70–90% (warning)
- Red — above 90% (error)
Get count programmatically:
const count: number = rteRef.current?.getCharCount();Source Code View
Add 'SourceCode' to toolbar items to let users toggle between the WYSIWYG view and the raw HTML source.
const toolbarSettings: ToolbarSettingsModel = { items: ['Bold', 'Italic', '|', 'SourceCode'] };
// Toggle source view programmatically
rteRef.current?.showSourceCode();Import and Export
Inject ImportExport to add Word import and Word/PDF export capabilities.
import { ImportExport } from '@syncfusion/ej2-react-richtexteditor';
const toolbarSettings: ToolbarSettingsModel = {
items: ['ImportWord', 'ExportWord', 'ExportPdf', '|', 'Bold', 'Italic']
};
const importWord: ImportWordModel = {
serviceUrl: 'url'
};
const exportWord: ExportWordModel = {
serviceUrl: 'url',
fileName: 'MyDocument.docx'
};
const exportPdf: ExportPdfModel = {
serviceUrl: 'url',
fileName: 'MyDocument.pdf'
};
<RichTextEditorComponent
toolbarSettings={toolbarSettings}
importWord={importWord}
exportWord={exportWord}
exportPdf={exportPdf}
>
<Inject services={[Toolbar, HtmlEditor, ImportExport]} />
</RichTextEditorComponent>Markdown Preview
In Markdown mode, render a live preview alongside the textarea using marked:
import { marked } from 'marked';
function rendereComplete() {
const textarea = (rteRef.current as any).contentModule.getEditPanel() as HTMLTextAreaElement;
textarea.addEventListener('keyup', () => {
if (previewRef.current) {
previewRef.current.innerHTML = marked(textarea.value) as string;
}
});
}
<RichTextEditorComponent
ref={rteRef}
editorMode="Markdown"
created={rendereComplete}
>
<Inject services={[Toolbar, MarkdownEditor]} />
</RichTextEditorComponent>
<div ref={previewRef} className="markdown-preview" />Placeholder Text
<RichTextEditorComponent placeholder="Start typing here...">
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>Style the placeholder via CSS:
.e-richtexteditor .e-rte-placeholder {
font-family: monospace;
color: #aaa;
font-style: italic;
}Encoded HTML Value
Set enableHtmlEncode={true} to store and retrieve content as HTML-encoded strings (e.g., <p> instead of <p>). Useful for safe storage and XSS prevention.
<RichTextEditorComponent enableHtmlEncode={true} value={encodedHtmlString}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>Enter Key & Selection in Syncfusion React Rich Text Editor
Table of Contents
Enter Key Configuration
By default, pressing Enter creates a new <p> paragraph tag. Change this to <br> or <div> to match your content requirements.
// Default: Enter creates a <p> tag
<RichTextEditorComponent enterKey="P">
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>
// Enter creates a <br> line break
<RichTextEditorComponent enterKey="BR">
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>
// Enter creates a <div> block
<RichTextEditorComponent enterKey="DIV">
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>When to use each:
P(default) — standard blog/article content where paragraphs are semantically correctBR— chat messages, compact text inputs where line breaks are expectedDIV— custom layout scenarios where<p>styling causes unwanted margins
Shift+Enter Key Configuration
Control what Shift + Enter produces (default: <br>):
<RichTextEditorComponent shiftEnterKey="P">
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>| Value | Output tag |
|---|---|
P | <p> — new paragraph |
BR | <br> — line break (default) |
DIV | <div> — new div block |
Selection API
Work with the current text selection in the editor:
const rteRef = useRef<RichTextEditorComponent>(null);
// Get selected text (plain text)
const getSelection = () => {
const selectedText = rteRef.current?.getSelection();
console.log('Selected:', selectedText);
};
// Select all content in the editor
const selectAll = () => {
rteRef.current?.selectAll();
};
// Get selection range
const getRange = () => {
const selection = window.getSelection();
if (selection && selection.rangeCount > 0) {
return selection.getRangeAt(0);
}
};Listening for selection changes:
const onSelect = (args: SelectEventArgs) => {
console.log('Selection changed:', args.requestType);
};
<RichTextEditorComponent select={onSelect}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>Cursor Positioning
Position cursor at end of content
After setting or updating the value, move the cursor to the end:
const rteRef = useRef<RichTextEditorComponent>(null);
const moveCursorToEnd = () => {
const rte = rteRef.current as any;
if (rte) {
const editPanel = rte.contentModule.getEditPanel();
const range = document.createRange();
const sel = window.getSelection();
range.selectNodeContents(editPanel);
range.collapse(false); // false = collapse to end
sel?.removeAllRanges();
sel?.addRange(range);
editPanel.focus();
}
};
useEffect(() => {
moveCursorToEnd();
}, []);Set cursor at a specific range
import { NodeSelection } from '@syncfusion/ej2-react-richtexteditor';
const setCursorAtRange = (range: Range) => {
const nodeSelection = new NodeSelection();
nodeSelection.setRange(document, range);
};Focus the editor programmatically
rteRef.current?.focusIn();Rich Text Editor Events
Table of Contents
- Lifecycle Events
- Content Change Events
- Action Events
- Toolbar Events
- Dialog & Popup Events
- Media & File Events
- Paste & Clipboard Events
- AI Assistant Events
- Resize Events
- Slash Menu & Selection Events
- Quick Toolbar Events
- Import / Export Events
---
Lifecycle Events
created — Type: object (plain)
Fires when the component is first rendered. Use it to run any post-mount logic. No typed arguments.
<RichTextEditorComponent created={() => console.log('RTE ready')}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>destroyed — Type: object (plain)
Fires when the component is destroyed (unmounted / destroy() called). No typed arguments.
<RichTextEditorComponent destroyed={() => console.log('RTE destroyed')}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>focus — Type: object (plain)
Fires when the editor gains focus. No typed arguments.
blur — Type: object (plain)
Fires when the editor loses focus. No typed arguments.
<RichTextEditorComponent
focus={() => console.log('focused')}
blur={() => console.log('blurred')}
>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>---
Content Change Events
change ← most commonly used — Type: ChangeEventArgs
Fires on focus-out when content has been modified.
| Arg | Type | Description |
|---|---|---|
value | string | Current HTML (or Markdown) content |
isInteracted | boolean | Whether the change was user-driven |
name | string | Event name |
import { ChangeEventArgs } from '@syncfusion/ej2-react-richtexteditor';
<RichTextEditorComponent change={(args: ChangeEventArgs) => {
console.log(args.value); // HTML string
}}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>Auto-Save Pattern:
<RichTextEditorComponent
value={content}
change={(args: ChangeEventArgs) => setContent(args.value)}
saveInterval={1000} // Fires change event every 1 second when idle
>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>---
Action Events
actionBegin — Type: ActionBeginEventArgs
Fires before a toolbar command executes. Set args.cancel = true to prevent it.
| Arg | Type | Description |
|---|---|---|
cancel | boolean | Set to true to abort the action |
requestType | string | The command being executed (e.g. 'Bold') |
selectType | string | Selection type |
originalEvent | `MouseEvent \ | KeyboardEvent \ |
name | string | Event name |
import { ActionBeginEventArgs } from '@syncfusion/ej2-react-richtexteditor';
<RichTextEditorComponent actionBegin={(args: ActionBeginEventArgs) => {
if (args.requestType === 'SourceCode') {
args.cancel = true; // block source code view
}
}}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>actionComplete — Type: ActionCompleteEventArgs
Fires after a toolbar command finishes.
| Arg | Type | Description |
|---|---|---|
requestType | string | The completed command |
editorMode | string | Current editor mode |
event | `MouseEvent \ | KeyboardEvent` |
name | string | Event name |
import { ActionCompleteEventArgs } from '@syncfusion/ej2-react-richtexteditor';
<RichTextEditorComponent actionComplete={(args: ActionCompleteEventArgs) => {
console.log('Completed:', args.requestType);
}}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>---
Toolbar Events
toolbarClick — Type: object (plain)
Fires when any toolbar item is clicked.
| Arg | Type | Description |
|---|---|---|
item | ToolbarItemModel | Clicked toolbar item |
originalEvent | Event | Source click event |
<RichTextEditorComponent toolbarClick={(args: any) => {
console.log('Toolbar item clicked:', args.item?.tooltipText);
}}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>updatedToolbarStatus — Type: ToolbarStatusEventArgs
Fires when toolbar item states (bold/italic/undo/redo active states) are refreshed.
| Arg | Type | Description |
|---|---|---|
undo | boolean | Whether undo is available |
redo | boolean | Whether redo is available |
html | object | HTML mode toolbar state map |
markdown | object | Markdown mode toolbar state map |
name | string | Event name |
Deprecated:toolbarStatusUpdate— useupdatedToolbarStatusinstead.
---
Dialog & Popup Events
beforeDialogOpen — Type: BeforeOpenEventArgs
Fires before any insert dialog (Image, Link, Table, etc.) opens. Cancel with args.cancel = true.
| Arg | Type | Description |
|---|---|---|
cancel | boolean | Set to prevent dialog open |
maxHeight | string | Dialog max height |
container | HTMLElement | Dialog container |
element | Element | Dialog element |
beforeDialogClose — Type: BeforeCloseEventArgs
Fires before any dialog closes. Cancel with args.cancel = true.
| Arg | Type | Description |
|---|---|---|
cancel | boolean | Set to prevent dialog close |
isInteracted | boolean | Whether user interacted |
container | HTMLElement | Dialog container |
element | Element | Dialog element |
event | Event | Triggered event |
closedBy | string (optional) | How dialog was closed |
import { BeforeOpenEventArgs, BeforeCloseEventArgs } from '@syncfusion/ej2-react-richtexteditor';
<RichTextEditorComponent
beforeDialogOpen={(args: BeforeOpenEventArgs) => {
console.log('Dialog about to open');
}}
beforeDialogClose={(args: BeforeCloseEventArgs) => {
if (someCondition) args.cancel = true; // prevent close
}}
>
<Inject services={[Toolbar, HtmlEditor, Image, Link]} />
</RichTextEditorComponent>dialogOpen / dialogClose — Type: object (plain)
Fire after a dialog opens or closes. No typed arguments.
beforePopupOpen / beforePopupClose — Type: BeforePopupOpenCloseEventArgs
Fire before any popup (emoji, link, image) opens or closes. Cancel with args.cancel = true.
| Arg | Type | Description |
|---|---|---|
cancel | boolean | Set to prevent popup open/close |
element | HTMLElement | Popup element |
originalEvent | Event | Source event |
popup | Popup | Popup instance |
type | EditorPopupType | Type of popup |
---
Media & File Events
Image Events
| Event | When | EventArgs Type |
|---|---|---|
imageSelected | Image file selected/dropped into the insert dialog | SelectedEventArgs |
imageUploading | During image upload progress | UploadingEventArgs |
imageUploadSuccess | Image upload succeeded | ImageSuccessEventArgs |
imageUploadFailed | Image upload failed | ImageFailedEventArgs |
imageRemoving | Image removed from the insert dialog | RemovingEventArgs |
afterImageDelete | Selected image removed from editor content | AfterImageDeleteEventArgs |
beforeImageDrop | Before dropping an image into the editor | ImageDropEventArgs |
Image Upload Success Example:
import { ImageSuccessEventArgs } from '@syncfusion/ej2-react-richtexteditor';
<RichTextEditorComponent
imageUploadSuccess={(args: ImageSuccessEventArgs) => {
// args.response — server response
// args.file — FileInfo
// args.element — the inserted <img> element
// args.detectImageSource — ImageInputSource
// args.operation — string
// args.statusText — string
const serverPath = JSON.parse(args.response.responseText).url;
(args.element as HTMLImageElement).setAttribute('src', serverPath);
}}
>
<Inject services={[Toolbar, HtmlEditor, Image]} />
</RichTextEditorComponent>Image Upload Failed Example:
import { ImageFailedEventArgs } from '@syncfusion/ej2-react-richtexteditor';
<RichTextEditorComponent
imageUploadFailed={(args: ImageFailedEventArgs) => {
console.log('Upload failed:', args.statusText);
console.log('File:', args.file);
}}
>
<Inject services={[Toolbar, HtmlEditor, Image]} />
</RichTextEditorComponent>Audio / Video Events
| Event | When | EventArgs Type |
|---|---|---|
fileSelected | Media file selected/dropped | SelectedEventArgs |
fileUploading | During media upload progress | UploadingEventArgs |
fileUploadSuccess | Media upload succeeded | object (plain) |
fileUploadFailed | Media upload failed | object (plain) |
fileRemoving | Media removed from insert dialog | RemovingEventArgs |
afterMediaDelete | Selected audio/video removed from editor | AfterMediaDeleteEventArgs |
beforeMediaDrop | Before dropping media into editor | MediaDropEventArgs |
---
Paste & Clipboard Events
beforePasteCleanup — Type: PasteCleanupArgs
Fires before pasted content is cleaned. Inspect or modify the pasted value.
| Arg | Type | Description |
|---|---|---|
value | string | Pasted HTML content |
filesData | FileInfo[] | Files attached to paste |
import { PasteCleanupArgs } from '@syncfusion/ej2-react-richtexteditor';
<RichTextEditorComponent
beforePasteCleanup={(args: PasteCleanupArgs) => {
console.log('Pasted value:', args.value);
}}
>
<Inject services={[Toolbar, HtmlEditor, PasteCleanup]} />
</RichTextEditorComponent>afterPasteCleanup — Type: object (plain)
Fires after paste cleanup finishes. No typed arguments.
beforeClipboardWrite — Type: ClipboardWriteEventArgs
Fires before writing to clipboard (copy/cut). Can be cancelled.
| Arg | Type | Description |
|---|---|---|
cancel | boolean | Set to prevent clipboard write |
clipboardData | DataTransfer | Clipboard data |
---
AI Assistant Events
aiAssistantPromptRequest — Type: AIAssistantPromptRequestArgs
Fires when the user submits a prompt in the AI Assistant. Use it to integrate a custom AI service instead of (or in addition to) the built-in serviceUrl.
| Arg | Type | Description |
|---|---|---|
cancel | boolean | Set true to cancel built-in request |
prompt | string | User's prompt text |
html | string | Selected HTML in editor |
text | string | Selected plain text |
promptSuggestions | string[] | Available suggestions |
responseToolbarItems | ToolbarItemModel[] | Response toolbar config |
import { AIAssistantPromptRequestArgs } from '@syncfusion/ej2-react-richtexteditor';
<RichTextEditorComponent
aiAssistantPromptRequest={async (args: AIAssistantPromptRequestArgs) => {
args.cancel = true; // handle manually
const reply = await myAIService(args.prompt, args.text);
rteRef.current?.addAIPromptResponse(reply, true);
}}
>
<Inject services={[Toolbar, HtmlEditor, AIAssistant]} />
</RichTextEditorComponent>aiAssistantToolbarClick — Type: AIAssitantToolbarClickEventArgs
Fires when the user clicks an item in the AI Assistant response toolbar.
| Arg | Type | Description |
|---|---|---|
cancel | boolean | Set to prevent default action |
requestType | AssistantToolbarType | Type of toolbar action |
item | IAIAssistantToolbarItem | Clicked item |
dataIndex | number | Index of AI response |
originalEvent | Event | Source event |
aiAssistantStopRespondingClick — Type: AIAssistantStopRespondingArgs
Fires when the user clicks "Stop responding" in the AI Assistant.
| Arg | Type | Description |
|---|---|---|
prompt | string | The prompt being responded to |
dataIndex | number | Index of AI response |
event | Event | Stop click event |
---
Resize Events
resizeStart / resizing / resizeStop — Type: ResizeArgs
Fire during resize operations (table cells, images, video, or editor body when enableResize is true).
| Arg | Type | Description |
|---|---|---|
cancel | boolean | Set on resizeStart to prevent resize |
event | `MouseEvent \ | TouchEvent` |
requestType | string | What is being resized |
import { ResizeArgs } from '@syncfusion/ej2-react-richtexteditor';
<RichTextEditorComponent
enableResize={true}
resizeStart={(args: ResizeArgs) => {
if (args.requestType === 'Image') {
args.cancel = true; // prevent image resize
}
}}
resizing={(args: ResizeArgs) => {
console.log('Resizing:', args.requestType);
}}
resizeStop={(args: ResizeArgs) => {
console.log('Resize stopped:', args.requestType);
}}
>
<Inject services={[Toolbar, HtmlEditor, Resize]} />
</RichTextEditorComponent>---
Slash Menu & Selection Events
slashMenuItemSelect — Type: SlashMenuItemSelectArgs
Fires when the user picks an item from the / slash menu.
| Arg | Type | Description |
|---|---|---|
itemData | ISlashMenuItem | The selected menu item |
item | HTMLLIElement | Item DOM element |
originalEvent | `MouseEvent \ | KeyboardEvent \ |
cancel | boolean (optional) | Set to prevent default action |
isInteracted | boolean (optional) | Whether user interacted |
import { SlashMenuItemSelectArgs } from '@syncfusion/ej2-react-richtexteditor';
<RichTextEditorComponent
slashMenuItemSelect={(args: SlashMenuItemSelectArgs) => {
if (args.itemData?.text === 'Table') {
args.cancel = true; // handle Table insertion yourself
}
}}
>
<Inject services={[Toolbar, HtmlEditor, SlashMenu]} />
</RichTextEditorComponent>selectionChanged — Type: SelectionChangedEventArgs
Fires when the user makes a non-empty text selection.
| Arg | Type | Description |
|---|---|---|
selectedContent | string | Selected HTML content |
selection | Selection | Selection object |
editorMode | `EditorMode \ | string` |
---
Quick Toolbar Events
beforeQuickToolbarOpen — Type: BeforeQuickToolbarOpenArgs
Fires before the quick (inline) toolbar opens. Cancel with args.cancel = true.
| Arg | Type | Description |
|---|---|---|
cancel | boolean | Set to prevent toolbar open |
targetElement | Element | Image/link/table that triggered the toolbar |
import { BeforeQuickToolbarOpenArgs } from '@syncfusion/ej2-react-richtexteditor';
<RichTextEditorComponent
beforeQuickToolbarOpen={(args: BeforeQuickToolbarOpenArgs) => {
if (args.targetElement.tagName === 'IMG') {
console.log('Opening quick toolbar for image');
}
}}
>
<Inject services={[Toolbar, HtmlEditor, Image, QuickToolbar]} />
</RichTextEditorComponent>quickToolbarOpen / quickToolbarClose — Type: object (plain)
Fire after the quick toolbar opens or closes. No typed arguments.
---
Import / Export Events
wordImporting — Type: UploadingEventArgs
Fires when a Word import upload begins. Use to add custom form data or headers.
| Arg | Type | Description |
|---|---|---|
fileData | FileInfo | Imported file info |
customFormData | { [key: string]: Object }[] | Custom form data to send |
cancel | boolean | Set to cancel import |
chunkSize | number (optional) | Upload chunk size |
currentChunkIndex | number (optional) | Current chunk index |
import { UploadingEventArgs } from '@syncfusion/ej2-react-richtexteditor';
<RichTextEditorComponent
wordImporting={(args: UploadingEventArgs) => {
args.customFormData = [{ userId: '123', dept: 'admin' }];
}}
>
<Inject services={[Toolbar, HtmlEditor, ImportExport]} />
</RichTextEditorComponent>documentExporting — Type: ExportingEventArgs
Fires before Word/PDF export request is sent. Use to add custom form data.
| Arg | Type | Description |
|---|---|---|
exportType | ExportDocumentType | 'Word' or 'Pdf' |
customFormData | { [key: string]: Object }[] | Custom form data to send |
currentRequest | { [key: string]: string }[] | Export request data |
import { ExportingEventArgs } from '@syncfusion/ej2-react-richtexteditor';
<RichTextEditorComponent
documentExporting={(args: ExportingEventArgs) => {
if (args.exportType === 'Word') {
args.customFormData = [{ userId: '42', format: 'docx' }];
}
}}
>
<Inject services={[Toolbar, HtmlEditor, ImportExport]} />
</RichTextEditorComponent>beforeSanitizeHtml — Type: BeforeSanitizeHtmlArgs
Fires before HTML sanitization (HTML mode only). Override sanitization rules or cancel.
| Arg | Type | Description |
|---|---|---|
cancel | boolean | Set to cancel sanitization |
selectors | SanitizeSelectors (optional) | Sanitization rules |
helper | Function (optional) | Sanitization helper function |
import { BeforeSanitizeHtmlArgs } from '@syncfusion/ej2-react-richtexteditor';
<RichTextEditorComponent
beforeSanitizeHtml={(args: BeforeSanitizeHtmlArgs) => {
// Custom sanitization logic
}}
>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>Getting Started with Syncfusion React Rich Text Editor
Installation
npm install @syncfusion/ej2-react-richtexteditorCSS Imports
Add these to your src/App.css. Use the theme that matches your app (tailwind3, material, bootstrap5, fluent2, etc.).
@import '../node_modules/@syncfusion/ej2-base/styles/tailwind3.css';
@import '../node_modules/@syncfusion/ej2-buttons/styles/tailwind3.css';
@import '../node_modules/@syncfusion/ej2-splitbuttons/styles/tailwind3.css';
@import '../node_modules/@syncfusion/ej2-inputs/styles/tailwind3.css';
@import '../node_modules/@syncfusion/ej2-lists/styles/tailwind3.css';
@import '../node_modules/@syncfusion/ej2-navigations/styles/tailwind3.css';
@import '../node_modules/@syncfusion/ej2-popups/styles/tailwind3.css';
@import '../node_modules/@syncfusion/ej2-richtexteditor/styles/tailwind3.css';Minimal Implementation
import { HtmlEditor, Image, Inject, Link, QuickToolbar, RichTextEditorComponent, Toolbar } from '@syncfusion/ej2-react-richtexteditor';
import './App.css';
function App() {
return (
<RichTextEditorComponent>
<Inject services={[Toolbar, Image, Link, HtmlEditor, QuickToolbar]} />
</RichTextEditorComponent>
);
}
export default App;Module Injection Pattern
The RTE uses a modular architecture — inject only the modules your feature requires. All modules are passed via the <Inject services={[...]} /> child component.
import { RichTextEditorComponent, Inject, Toolbar, HtmlEditor, Link, Image, QuickToolbar, Table, PasteCleanup, Count } from '@syncfusion/ej2-react-richtexteditor';
function App() {
return (
<RichTextEditorComponent height={450}>
<Inject services={[Toolbar, HtmlEditor, Link, Image, QuickToolbar, Table, PasteCleanup, Count]} />
</RichTextEditorComponent>
);
}Omitting a module silently disables its feature. If image upload isn't working, check that Image is injected.Basic Toolbar Configuration
Use toolbarSettings.items to specify which toolbar buttons appear.
const toolbarSettings: ToolbarSettingsModel = {
items: [
'Bold', 'Italic', 'Underline', 'StrikeThrough',
'FontName', 'FontSize', 'FontColor', 'BackgroundColor', '|',
'Formats', 'Alignments', 'OrderedList', 'UnorderedList',
'Outdent', 'Indent', '|',
'CreateLink', 'Image', '|',
'ClearFormat', 'Print', 'SourceCode', 'FullScreen', '|',
'Undo', 'Redo'
]
};
function App() {
return (
<RichTextEditorComponent height={450} toolbarSettings={toolbarSettings}>
<Inject services={[Toolbar, Image, Link, HtmlEditor, QuickToolbar]} />
</RichTextEditorComponent>
);
}Use|for a vertical separator and-for a horizontal separator in the toolbar.
Setting Initial Content
Pass HTML string via the value prop:
const content: string = `<p>Welcome to <b>Syncfusion</b> Rich Text Editor.</p>
<ul>
<li>WYSIWYG editing</li>
<li>Markdown support</li>
<li>Media insertion</li>
</ul>`;
function App() {
return (
<RichTextEditorComponent value={content} height={450}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>
);
}Run the App
npm run devCommon Setup Gotchas
- Missing styles: All the
@syncfusion/ej2-*CSS imports are required — the RTE uses styles from multiple packages. - Blank toolbar: Ensure
Toolbaris in the injected services ANDtoolbarSettings.itemsis configured. - Image upload fails:
Imagemodule must be injected; also configureinsertImageSettings.saveUrlfor server upload. - TypeScript errors: Import types like
ToolbarSettingsModelfrom@syncfusion/ej2-react-richtexteditor.
How-To Guides for Syncfusion React Rich Text Editor
Table of Contents
- Capture Ctrl Keys to Update the Value
- Change Default Font Family
- Check Image Size on Upload
- Customize Placeholder Style
- Customize Shortcut Keys
- File Attachment
- Format Code Blocks
- Position Cursor at End of Content
- Rename Images on Server
- RTE Inside a Dialog
- RTE Inside a Tab
- Set Cursor at Specific Range
- Tailwind CSS Preflight Fix
- Update Value Programmatically
---
Capture Ctrl Keys to Update the Value
Capture Ctrl+S or other key combos to trigger a manual save:
const onKeyDown = (args: KeyboardEvent) => {
if (args.ctrlKey && args.key === 's') {
args.preventDefault();
const value = rteRef.current?.value;
saveToServer(value);
}
};
<RichTextEditorComponent
ref={rteRef}
keyDown={onKeyDown as any}
>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>---
Change Default Font Family
Set the default font by overriding the editor's CSS and optionally configuring the font picker:
/* Override editor content area font */
.e-richtexteditor .e-rte-content {
font-family: 'Segoe UI', sans-serif;
}For the font picker dropdown default:
const fontFamily: FontFamilyModel = {
default: 'Segoe UI',
items: [
{ text: 'Segoe UI', value: 'Segoe UI' },
{ text: 'Arial', value: 'Arial,Helvetica,sans-serif' },
{ text: 'Georgia', value: 'Georgia,serif' },
]
};
<RichTextEditorComponent fontFamily={fontFamily}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>---
Check Image Size on Upload
Validate image file size before allowing the upload using the imageUploadFailed or beforeImageUpload event:
const beforeImageUpload = (args: ImageUploadingEventArgs) => {
const file = args.filesData[0].rawFile as File;
const maxSizeKB = 500;
if (file.size / 1024 > maxSizeKB) {
args.cancel = true;
alert(`Image size exceeds ${maxSizeKB}KB. Please upload a smaller file.`);
}
};
<RichTextEditorComponent
insertImageSettings={{ saveUrl: 'url' }}
beforeImageUpload={beforeImageUpload}
>
<Inject services={[Toolbar, HtmlEditor, Image, QuickToolbar]} />
</RichTextEditorComponent>---
Customize Placeholder Style
Target the .e-rte-placeholder class to style the placeholder text:
.e-richtexteditor .e-rte-placeholder {
font-family: 'Georgia', serif;
color: #aaa;
font-style: italic;
font-size: 16px;
}---
Customize Shortcut Keys
Override default shortcuts by configuring the formatter:
const customShortcuts = {
keyConfig: {
bold: 'ctrl+alt+b',
italic: 'ctrl+alt+i',
underline: 'ctrl+alt+u',
}
};
<RichTextEditorComponent formatter={customShortcuts}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>---
File Attachment
To support file attachments (non-image files), handle them via the fileAttachmentInserted event or integrate the FileManager module. For custom file attachments with a server upload:
const insertFileLink = (fileName: string, fileUrl: string) => {
const html = `<a href="${fileUrl}" target="_blank">${fileName}</a>`;
rteRef.current?.executeCommand('insertHTML', html);
};
// Call after uploading file to your server:
insertFileLink('report.pdf', 'url');---
Format Code Blocks
Using the CodeBlock module for inline code:
import { CodeBlock } from '@syncfusion/ej2-react-richtexteditor';
const toolbarSettings: ToolbarSettingsModel = { items: ['CodeBlock', 'Bold', 'Italic'] };
<RichTextEditorComponent toolbarSettings={toolbarSettings}>
<Inject services={[Toolbar, HtmlEditor, CodeBlock]} />
</RichTextEditorComponent>For multi-line code blocks, use Pre from the Formats dropdown or insert a <pre> block programmatically:
rteRef.current?.executeCommand('insertHTML', '<pre><code>const x = 1;</code></pre>');---
Position Cursor at End of Content
After setting new content or on component creation, move the cursor to the end:
const onCreated = () => {
const rte = rteRef.current as any;
const editPanel = rte.contentModule.getEditPanel();
const range = document.createRange();
const sel = window.getSelection();
range.selectNodeContents(editPanel);
range.collapse(false);
sel?.removeAllRanges();
sel?.addRange(range);
};
<RichTextEditorComponent ref={rteRef} created={onCreated}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>---
Rename Images on Server
Use imageUploadSuccess to update the image src after the server renames the file:
const onImageUploadSuccess = (args: ImageSuccessEventArgs) => {
if (args.e.currentTarget.getResponseHeader('name')) {
const newName = args.e.currentTarget.getResponseHeader('name');
const imgUrl = `url/${newName}`;
(args.file as any).statusCode = '2'; // success
args.file.name = newName;
// Update the image src in the editor
const img = (rteRef.current as any).element.querySelector(`img[data-upload-id="${args.file.id}"]`);
if (img) img.src = imgUrl;
}
};---
RTE Inside a Dialog
When the RTE is inside a dialog (e.g., Syncfusion DialogComponent), the toolbar may not render correctly on first open. Refresh the editor after the dialog opens:
const onDialogOpen = () => {
setTimeout(() => {
rteRef.current?.refresh();
}, 100);
};
<DialogComponent opened={onDialogOpen}>
<RichTextEditorComponent ref={rteRef}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>
</DialogComponent>---
RTE Inside a Tab
Similar to dialog — when a tab containing the RTE becomes active, refresh it:
const onTabSelect = (args: SelectEventArgs) => {
if (args.selectedIndex === 1) { // the tab index containing RTE
setTimeout(() => {
rteRef.current?.refresh();
}, 100);
}
};---
Set Cursor at Specific Range
Save a range and restore it later (useful for custom toolbar actions):
import { NodeSelection } from '@syncfusion/ej2-react-richtexteditor';
let savedRange: Range;
const nodeSelection = new NodeSelection();
// Save current cursor position
const saveRange = () => {
savedRange = nodeSelection.getRange(document);
};
// Restore saved cursor position
const restoreRange = () => {
if (savedRange) {
nodeSelection.setRange(document, savedRange);
}
};---
Tailwind CSS Preflight Fix
If Tailwind's preflight resets are breaking the RTE's styles (buttons appearing unstyled, margins wrong), scope the conflict:
/* In your tailwind.css / global.css */
/* Option 1: Disable preflight in tailwind.config.js */
/* corePlugins: { preflight: false } */
/* Option 2: Reset Tailwind overrides inside RTE only */
.e-richtexteditor button {
all: revert;
}
.e-richtexteditor * {
box-sizing: content-box;
}Or in tailwind.config.js:
module.exports = {
corePlugins: {
preflight: false,
},
};---
Update Value Programmatically
Set the editor's value after mount using the ref:
// Via property assignment
rteRef.current.value = '<p>New content</p>';
// Via property + dataBind (forces re-render)
if (rteRef.current) {
rteRef.current.value = '<p>Updated content</p>';
rteRef.current.dataBind();
}For React state-driven updates, just update the state variable bound to value:
setContent('<p>Updated via state</p>');Inserting Content in Syncfusion React Rich Text Editor
Table of Contents
Inserting Tables
Inject Table and add 'CreateTable' to toolbar items. The editor provides a grid picker to choose rows and columns.
import { HtmlEditor, Image, Inject, Link, Table, QuickToolbar, RichTextEditorComponent, Toolbar } from '@syncfusion/ej2-react-richtexteditor';
const toolbarSettings: ToolbarSettingsModel = {
items: ['Bold', 'Italic', '|', 'CreateTable', '|', 'Undo', 'Redo']
};
function App() {
return (
<RichTextEditorComponent toolbarSettings={toolbarSettings}>
<Inject services={[Toolbar, HtmlEditor, Table, QuickToolbar]} />
</RichTextEditorComponent>
);
}Table Quick Toolbar
When QuickToolbar is injected, clicking a table cell shows a context toolbar for table editing. Customize with quickToolbarSettings.table:
const quickToolbarSettings: QuickToolbarSettingsModel = {
table: [
'TableHeader', 'TableRows', 'TableColumns', 'TableCell', '|',
'BackgroundColor', 'TableRemove', 'TableCellVerticalAlign', 'Styles'
]
};
<RichTextEditorComponent quickToolbarSettings={quickToolbarSettings}>
<Inject services={[Toolbar, HtmlEditor, Table, QuickToolbar]} />
</RichTextEditorComponent>Table Styles
The Styles quick toolbar item provides options to apply alternate row styling and border styles to the table.
Inserting Hyperlinks
Inject Link and add 'CreateLink' to toolbar items. Users can insert, edit, open, and remove links via the link dialog.
const toolbarSettings: ToolbarSettingsModel = {
items: ['Bold', 'Italic', '|', 'CreateLink', '|', 'Undo', 'Redo']
};
function App() {
return (
<RichTextEditorComponent toolbarSettings={toolbarSettings}>
<Inject services={[Toolbar, HtmlEditor, Link, QuickToolbar]} />
</RichTextEditorComponent>
);
}Configuring Link Settings
// Auto-detect and convert URLs to links as user types
<RichTextEditorComponent enableAutoUrl={true}>
<Inject services={[Toolbar, HtmlEditor, Link]} />
</RichTextEditorComponent>Link Quick Toolbar
Clicking on an inserted link shows the quick toolbar:
const quickToolbarSettings: QuickToolbarSettingsModel = {
link: ['Open', 'Edit', 'UnLink']
};Code Blocks
Inject CodeBlock and add 'CodeBlock' to toolbar items. This formats selected inline text as a code snippet with syntax-aware styling.
import { CodeBlock } from '@syncfusion/ej2-react-richtexteditor';
const toolbarSettings = {
items: ['Bold', 'Italic', '|', 'CodeBlock', '|', 'Undo', 'Redo']
};
function App() {
return (
<RichTextEditorComponent toolbarSettings={toolbarSettings}>
<Inject services={[Toolbar, HtmlEditor, CodeBlock]} />
</RichTextEditorComponent>
);
}CodeBlockformats selected text as<code>tags. For full code editor panels, consider integrating CodeMirror (see styling-customization.md).
Custom Format Blocks
Use the Formats toolbar item to apply block-level formatting. You can customize the available format options:
const format: FormatModel = {
items: [
{ text: 'Paragraph', value: 'P' },
{ text: 'Heading 1', value: 'H1' },
{ text: 'Heading 2', value: 'H2' },
{ text: 'Heading 3', value: 'H3' },
{ text: 'Blockquote', value: 'BlockQuote' },
{ text: 'Preformatted', value: 'Pre' },
{ text: 'Code', value: 'Code' },
]
};
const toolbarSettings = { items: ['Formats'] };
<RichTextEditorComponent toolbarSettings={toolbarSettings} format={format}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>AutoFormat Module
Inject AutoFormat to automatically convert Markdown syntax into HTML while the user types — for example typing **word** converts to bold without needing the toolbar.
import { AutoFormat } from '@syncfusion/ej2-react-richtexteditor';
<RichTextEditorComponent>
<Inject services={[Toolbar, HtmlEditor, AutoFormat]} />
</RichTextEditorComponent>Supported auto-conversions include: **bold**, *italic*, ~~strikethrough~~, headings, lists, blockquotes, and horizontal rules.
Inserting Media in Syncfusion React Rich Text Editor
Table of Contents
- Inserting Images
- Image Save Formats
- Server-Side Image Upload
- Inserting Videos
- Inserting Audio
- File Browser Integration
Inserting Images
Inject the Image module and add 'Image' to toolbar items. Users can insert images via URL or file upload from the insert image dialog.
import {
HtmlEditor, Image, Inject, Link,
QuickToolbar, RichTextEditorComponent, Toolbar
} from '@syncfusion/ej2-react-richtexteditor';
const toolbarSettings: ToolbarSettingsModel = { items: ['Image', 'Bold', 'Italic'] };
function App() {
return (
<RichTextEditorComponent height={450} toolbarSettings={toolbarSettings}>
<Inject services={[Toolbar, Image, Link, HtmlEditor, QuickToolbar]} />
</RichTextEditorComponent>
);
}Configuring Image Insert Settings
Use insertImageSettings to control how images are saved and displayed:
const insertImageSettings: ImageSettingsModel = {
saveFormat: 'Base64', // 'Base64' or 'Blob'
width: '300px', // default image width
height: 'auto', // default image height
minWidth: '10px',
minHeight: '10px',
maxWidth: '100%',
maxHeight: '600px',
display: 'inline', // 'inline' or 'break' (block)
allowedTypes: ['.jpg', '.png', '.gif', '.webp'], // restrict file types
};
<RichTextEditorComponent insertImageSettings={insertImageSettings}>
<Inject services={[Toolbar, Image, HtmlEditor, QuickToolbar]} />
</RichTextEditorComponent>Image Save Formats
| Format | Behavior |
|---|---|
Base64 | Image is embedded as a base64 data URL in the HTML. No server required. Best for small images. |
Blob | Image is saved as a blob URL (blob:http://...). Ephemeral — use with saveUrl for persistence. |
// Base64 embedding (no server needed)
const insertImageSettings: ImageSettingsModel = { saveFormat: 'Base64' };
// Blob with server upload
const insertImageSettings: ImageSettingsModel = {
saveFormat: 'Blob',
saveUrl: 'url',
path: 'url'
};Server-Side Image Upload
Configure saveUrl for automatic upload when images are inserted via the dialog:
const insertImageSettings: ImageSettingsModel = {
saveUrl: 'url',
path: 'url',
// Optionally remove saved images
removeUrl: 'url',
};
<RichTextEditorComponent insertImageSettings={insertImageSettings}>
<Inject services={[Toolbar, Image, HtmlEditor, QuickToolbar]} />
</RichTextEditorComponent>Handle the `imageUploadSuccess` event to process the server's response:
const onImageUploadSuccess = (args: ImageSuccessEventArgs) => {
// args.e.currentTarget.response — server JSON response
const response = JSON.parse(args.e.currentTarget.response);
args.file.name = response.name; // update image name if server renames it
};
<RichTextEditorComponent
insertImageSettings={insertImageSettings}
imageUploadSuccess={onImageUploadSuccess}
>
<Inject services={[Toolbar, Image, HtmlEditor, QuickToolbar]} />
</RichTextEditorComponent>Inserting Videos
Inject Video and add 'Video' to toolbar items. Supports embedded video URLs (YouTube, Vimeo) and direct file uploads.
import { Video } from '@syncfusion/ej2-react-richtexteditor';
const toolbarSettings: ToolbarSettingsModel = { items: ['Video', 'Bold'] };
const insertVideoSettings: VideoSettingsModel = {
saveUrl: 'url',
path: 'url',
minWidth: '100px',
minHeight: '70px',
width: '300px',
height: '200px',
};
function App() {
return (
<RichTextEditorComponent
toolbarSettings={toolbarSettings}
insertVideoSettings={insertVideoSettings}
>
<Inject services={[Toolbar, HtmlEditor, Video, QuickToolbar]} />
</RichTextEditorComponent>
);
}Inserting Audio
Inject Audio and add 'Audio' to toolbar items. Supports URL embedding and file upload.
import { Audio } from '@syncfusion/ej2-react-richtexteditor';
const toolbarSettings: ToolbarSettingsModel = { items: ['Audio', 'Bold'] };
const insertAudioSettings: AudioSettingsModel = {
saveUrl: 'url',
path: 'url',
allowedTypes: ['.mp3', '.wav', '.ogg'],
};
function App() {
return (
<RichTextEditorComponent
toolbarSettings={toolbarSettings}
insertAudioSettings={insertAudioSettings}
>
<Inject services={[Toolbar, HtmlEditor, Audio, QuickToolbar]} />
</RichTextEditorComponent>
);
}File Browser Integration
Inject FileManager to let users browse files from a server-side file system and insert them directly into the editor.
import { FileManager } from '@syncfusion/ej2-react-richtexteditor';
const fileManagerSettings: FileManagerSettingsModel = {
enable: true,
path: '/Pictures/Food',
ajaxSettings: {
url: 'url',
getImageUrl: 'url',
uploadUrl: 'url',
downloadUrl: 'url'
}
};
const toolbarSettings: ToolbarSettingsModel = { items: ['Image'] };
function App() {
return (
<RichTextEditorComponent
toolbarSettings={toolbarSettings}
fileManagerSettings={fileManagerSettings}
>
<Inject services={[Toolbar, HtmlEditor, Image, FileManager, QuickToolbar]} />
</RichTextEditorComponent>
);
}The FileManager module requires a server-side file management controller. See Syncfusion's FileManager documentation for the API contract.Rich Text Editor Methods
Table of Contents
- Focus & Content Methods
- Toolbar Methods
- Dialog Methods
- Selection Methods
- Undo / Redo Methods
- AI Assistant Methods
- Utility Methods
- Using Methods via Ref
---
Using Methods via Ref
Access all public methods through a React ref:
import { useRef } from 'react';
import { RichTextEditorComponent, Inject, Toolbar, HtmlEditor } from '@syncfusion/ej2-react-richtexteditor';
function App() {
const rteRef = useRef<RichTextEditorComponent>(null);
const handleGetContent = () => {
const html = rteRef.current?.getHtml();
console.log(html);
};
return (
<>
<button onClick={handleGetContent}>Get HTML</button>
<RichTextEditorComponent ref={rteRef}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>
</>
);
}---
Focus & Content Methods
focusIn(): void
Programmatically focus the editor.
rteRef.current?.focusIn();focusOut(): void
Remove focus from the editor.
rteRef.current?.focusOut();getHtml(): string
Returns the full HTML content of the editor.
const html: string = rteRef.current?.getHtml();getText(): string
Returns the plain text content (HTML tags stripped).
const text: string = rteRef.current?.getText();getContent(): Element
Returns the inner Element node of the editor content area.
const el: Element = rteRef.current?.getContent();getSelectedHtml(): string
Returns the HTML of the currently selected text.
const selectedHtml: string = rteRef.current?.getSelectedHtml();getSelection(): string
Returns the HTML markup of the current selection.
const sel: string = rteRef.current?.getSelection();getXhtml(): string
Returns XHTML-validated HTML. Only meaningful when enableXhtml={true}.
const xhtml: string = rteRef.current?.getXhtml();getCharCount(): number
Returns the current character count.
const count: number = rteRef.current?.getCharCount();print(): void
Opens the browser print dialog for the editor content.
rteRef.current?.print();refreshUI(): void
Re-renders the editor view. Useful after programmatic DOM changes.
rteRef.current?.refreshUI();showSourceCode(): void
Toggles the HTML source code view on/off.
rteRef.current?.showSourceCode();showFullScreen(): void
Expands the editor into full-screen mode.
rteRef.current?.showFullScreen();sanitizeHtml(value: string): string
Sanitizes an HTML string against XSS. Applicable when editor mode is HTML.
const clean: string = rteRef.current?.sanitizeHtml('<script>alert(1)</script><p>safe</p>');
// → '<p>safe</p>'---
Toolbar Methods
enableToolbarItem(items: string | string[], muteToolbarUpdate?: boolean): void
Enables one or more toolbar items by name.
rteRef.current?.enableToolbarItem(['Bold', 'Italic']);disableToolbarItem(items: string | string[], muteToolbarUpdate?: boolean): void
Disables one or more toolbar items.
rteRef.current?.disableToolbarItem('Image');Set muteToolbarUpdate: true to suppress the visual toolbar refresh when updating multiple items.removeToolbarItem(items: string | string[]): void
Permanently removes toolbar items from the toolbar.
rteRef.current?.removeToolbarItem(['CreateLink', 'Image']);hideInlineToolbar(): void
Hides the inline/quick toolbar if it is open.
rteRef.current?.hideInlineToolbar();showInlineToolbar(): void
Forces the inline/quick toolbar to display.
rteRef.current?.showInlineToolbar();---
Dialog Methods
showDialog(type: DialogType): void
Programmatically opens an insert dialog.
import { DialogType } from '@syncfusion/ej2-react-richtexteditor';
rteRef.current?.showDialog(DialogType.InsertImage);
rteRef.current?.showDialog(DialogType.InsertLink);
rteRef.current?.showDialog(DialogType.InsertTable);
rteRef.current?.showDialog(DialogType.InsertAudio);
rteRef.current?.showDialog(DialogType.InsertVideo);closeDialog(type: DialogType): void
Programmatically closes an open dialog.
rteRef.current?.closeDialog(DialogType.InsertImage);showEmojiPicker(x?: number, y?: number): void
Opens the emoji picker. Optionally position it at (x, y).
rteRef.current?.showEmojiPicker();
rteRef.current?.showEmojiPicker(200, 400); // positioned---
Selection Methods
selectAll(): void
Selects all content in the editor.
rteRef.current?.selectAll();getRange(): Range
Returns the current Range object from the editor's selection.
const range: Range = rteRef.current?.getRange();selectRange(range: Range): void
Restores a previously captured range (useful for re-focusing after an async operation).
const range = rteRef.current?.getRange();
// ... do something async ...
rteRef.current?.selectRange(range);---
Undo / Redo Methods
clearUndoRedo(): void
Clears both the undo and redo stacks and disables their toolbar buttons.
rteRef.current?.clearUndoRedo();---
AI Assistant Methods
executeAIPrompt(prompt: string): void
Sends a prompt string directly to the AI Assistant for processing.
rteRef.current?.executeAIPrompt('Summarize the selected text');addAIPromptResponse(outputResponse: string | Object, isFinalUpdate?: boolean): void
Adds a response to the AI Assistant's last prompt, or appends a new prompt+response object.
outputResponse: Markdown string (auto-converted to HTML) or an object with prompt+response.isFinalUpdate: Passtruewhen the complete streamed response has been received (hides the stop button).
// Streaming response — call multiple times, then finalize:
rteRef.current?.addAIPromptResponse('Here is a partial...', false);
rteRef.current?.addAIPromptResponse('... and the full answer.', true);getAIPromptHistory(): PromptModel[]
Returns the full conversation history (prompts + responses) from the AI Assistant.
const history = rteRef.current?.getAIPromptHistory();
console.log(history); // PromptModel[]clearAIPromptHistory(): void
Clears all AI Assistant conversation history.
rteRef.current?.clearAIPromptHistory();showAIAssistantPopup(): void
Programmatically opens the AI Assistant popup.
rteRef.current?.showAIAssistantPopup();hideAIAssistantPopup(): void
Programmatically closes the AI Assistant popup.
rteRef.current?.hideAIAssistantPopup();---
Utility Methods
executeCommand(commandName: CommandName, value?, option?): void
Executes a built-in editor command programmatically. Covers all formatting, insertion, and navigation commands.
Common `CommandName` values:
| Command | Effect |
|---|---|
'bold' | Toggle bold on selection |
'italic' | Toggle italic |
'underline' | Toggle underline |
'insertHTML' | Insert raw HTML at cursor |
'insertText' | Insert plain text at cursor |
'insertImage' | Insert an image |
'insertLink' | Insert a hyperlink |
'insertTable' | Insert a table |
'insertAudio' | Insert audio |
'insertVideo' | Insert video |
'undo' | Undo last action |
'redo' | Redo last undone action |
'removeFormat' | Strip formatting from selection |
'importWord' | Trigger Word import |
import { CommandName } from '@syncfusion/ej2-react-richtexteditor';
// Insert bold text
rteRef.current?.executeCommand('bold');
// Insert HTML at cursor
rteRef.current?.executeCommand('insertHTML', '<strong>Injected</strong>');
// Insert a link
rteRef.current?.executeCommand('insertLink', {
url: 'https://syncfusion.com',
text: 'Syncfusion',
title: 'Syncfusion website',
target: '_blank',
selection: null
});
// Insert an image
rteRef.current?.executeCommand('insertImage', {
url: 'url',
altText: 'Example image',
width: { width: '300px' },
height: { height: 'auto' },
selection: null
});
// Insert a table (3 columns × 2 rows)
rteRef.current?.executeCommand('insertTable', {
rows: 2,
columns: 3,
selection: null
});destroy(): void
Destroys the component, removing all event handlers, attributes, and DOM content.
rteRef.current?.destroy();Paste & Clipboard in Syncfusion React Rich Text Editor
Table of Contents
Paste Cleanup
When users paste content from Word, websites, or other editors, it often carries inline styles, classes, and tags that break the editor's visual consistency. Inject PasteCleanup to automatically clean pasted content.
import { PasteCleanup } from '@syncfusion/ej2-react-richtexteditor';
function App() {
return (
<RichTextEditorComponent>
<Inject services={[Toolbar, HtmlEditor, PasteCleanup]} />
</RichTextEditorComponent>
);
}Paste Cleanup Configuration
Use pasteCleanupSettings to control what gets removed or kept:
const pasteCleanupSettings = {
prompt: true, // Show a dialog asking user to choose paste mode
plainText: false, // Paste as plain text (strips all formatting)
keepFormat: false, // Keep source formatting
deniedTags: ['a'], // Remove these tags from pasted content
deniedAttrs: ['class', 'id', 'style'], // Remove these attributes
allowedStyleProps: ['color', 'font-size', 'font-weight'], // Keep only these CSS properties
};
<RichTextEditorComponent pasteCleanupSettings={pasteCleanupSettings}>
<Inject services={[Toolbar, HtmlEditor, PasteCleanup]} />
</RichTextEditorComponent>Paste modes:
prompt: true— dialog lets user pick between "Keep Text Only", "Keep Formatting", or "Clean Up CSS"plainText: true— always paste as plain text, stripping all HTMLkeepFormat: true— always keep source formatting (default behavior without PasteCleanup)
Handling the afterPasteCleanup Event
const afterPasteCleanup = (args: PasteCleanupArgs) => {
console.log('Cleaned paste content:', args.value);
}
<RichTextEditorComponent
pasteCleanupSettings={pasteCleanupSettings}
afterPasteCleanup={afterPasteCleanup}
>
<Inject services={[Toolbar, HtmlEditor, PasteCleanup]} />
</RichTextEditorComponent>Clipboard Cleanup
Inject ClipboardCleanup to clean content automatically when users copy or cut from the editor. This removes unwanted inline styles while preserving the content structure — useful when users copy from the RTE and paste into another application.
import { ClipboardCleanup } from '@syncfusion/ej2-react-richtexteditor';
<RichTextEditorComponent>
<Inject services={[Toolbar, HtmlEditor, ClipboardCleanup]} />
</RichTextEditorComponent>ClipboardCleanup operates silently on copy/cut. No configuration needed for basic use.Exec Command
Use executeCommand to programmatically apply formatting or insert content at the cursor position.
const rteRef = useRef<RichTextEditorComponent>(null);
// Apply bold to current selection
rteRef.current?.executeCommand('bold');
// Insert HTML at cursor
rteRef.current?.executeCommand('insertHTML', '<strong>Inserted text</strong>');
// Insert plain text
rteRef.current?.executeCommand('insertText', 'Hello World');
// Create a link around selected text
rteRef.current?.executeCommand('createLink', {
url: 'https://syncfusion.com',
text: 'Syncfusion',
title: 'Go to Syncfusion'
});Common commands:
| Command | Description |
|---|---|
bold | Toggle bold on selection |
italic | Toggle italic on selection |
underline | Toggle underline on selection |
insertHTML | Insert HTML at cursor |
insertText | Insert plain text at cursor |
createLink | Wrap selection in a link |
insertImage | Insert image at cursor |
fontSize | Set font size (e.g., '14pt') |
fontName | Set font family |
foreColor | Set text color |
backColor | Set background color |
Always check that the RTE is focused before running executeCommand, otherwise the cursor position may be lost.Rich Text Editor Properties
Table of Contents
- Core Properties
- Toolbar Properties
- Editor Mode & Behavior
- Value & Content Properties
- Media Insert Properties
- Font, Color & Format Properties
- Paste & Clipboard Properties
- Table Properties
- AI Assistant Properties
- Slash Menu Properties
- Import / Export Properties
- Miscellaneous Properties
---
Core Properties
| Property | Type | Default | Description |
|---|---|---|---|
height | `string \ | number` | 'auto' |
width | `string \ | number` | '100%' |
enabled | boolean | true | Enable/disable the editor |
readonly | boolean | false | Makes the editor read-only |
placeholder | string | '' | Placeholder text when empty |
cssClass | string | null | Additional CSS class(es) on the root element |
htmlAttributes | {[key: string]: string} | {} | Extra HTML attributes on the root element |
locale | string | '' | Override locale (default: 'en-US') |
showTooltip | boolean | true | Show/hide toolbar tooltips |
<RichTextEditorComponent
height={450}
width="100%"
placeholder="Start typing here..."
readonly={false}
cssClass="my-custom-editor"
>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>---
Toolbar Properties
Important Enum Imports
When working with toolbar and editor configurations, you may need to import specific enums:
import {
ToolbarType, // For toolbarSettings.type
EditorMode, // For editorMode property
SaveFormat, // For insertImageSettings.saveFormat
// ... other enums as needed
} from '@syncfusion/ej2-react-richtexteditor';toolbarSettings: ToolbarSettingsModel
Controls the main toolbar appearance and content.
| Property | Type | Description |
|---|---|---|
enable | boolean | Show/hide the toolbar |
enableFloating | boolean | Sticky floating toolbar on scroll |
items | `(string \ | ToolbarItems)[]` |
position | `'Top' \ | 'Bottom'` |
type | ToolbarType | Toolbar overflow behavior (ToolbarType.Expand \ |
Important: The type property requires the ToolbarType enum, not a string literal. Import it from @syncfusion/ej2-react-richtexteditor.
import { ToolbarType } from '@syncfusion/ej2-react-richtexteditor';
const toolbarSettings: ToolbarSettingsModel = {
enable: true,
enableFloating: true,
position: 'Top',
type: ToolbarType.Expand, // Use enum, not string
items: [
'Bold', 'Italic', 'Underline', '|',
'Formats', 'Alignments', '|',
'OrderedList', 'UnorderedList', '|',
'CreateLink', 'Image', 'Table', '|',
'Undo', 'Redo'
]
};quickToolbarSettings: QuickToolbarSettingsModel
Inline toolbar that appears when selecting images, links, or tables.
floatingToolbarOffset: number
Pixel offset from the top of the page for the floating toolbar. Default: 0.
---
Editor Mode & Behavior
editorMode: EditorMode
Sets the editing mode. Default: 'HTML'.
Available modes:
'HTML'— WYSIWYG HTML editor'Markdown'— Markdown textarea with preview support
Note: Can be used as a string literal or EditorMode enum.
import { EditorMode } from '@syncfusion/ej2-react-richtexteditor';
// Using string literal (both work)
<RichTextEditorComponent editorMode="Markdown">
<Inject services={[Toolbar, MarkdownEditor]} />
</RichTextEditorComponent>
// Using enum
<RichTextEditorComponent editorMode={EditorMode.Markdown}>
<Inject services={[Toolbar, MarkdownEditor]} />
</RichTextEditorComponent>iframeSettings: IFrameSettingsModel
Enables iFrame mode for full CSS isolation.
| Property | Type | Description |
|---|---|---|
enable | boolean | Render editor in an <iframe> |
resources | {styles: string[]; scripts: string[]} | External CSS/JS to inject into iframe |
attributes | object | Attributes for the iframe body |
sandbox | string[] | Sandbox flags |
const iframeSettings: IFrameSettingsModel = {
enable: true,
resources: {
styles: ['url']
}
};inlineMode: InlineModeModel
Enables inline editing (toolbar appears on selection rather than always visible).
const inlineMode: InlineModeModel = { enable: true, onSelection: true };enterKey: EnterKey
Controls what tag is inserted when Enter is pressed.
'P'(default) — inserts<p><br></p>'DIV'— inserts<div>'BR'— inserts<br>
<RichTextEditorComponent enterKey="BR">
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>enableTabKey: boolean
Allows the Tab key to insert a tab character in the editor. Default: false.
enableResize: boolean
Adds a resize handle to the bottom-right of the editor. Default: false.
enableRtl: boolean
Renders the editor in right-to-left direction. Default: false.
enablePersistence: boolean
Persists the editor value across page reloads using localStorage. Default: false.
---
Value & Content Properties
| Property | Type | Default | Description |
|---|---|---|---|
value | string | null | HTML or Markdown content |
valueTemplate | `string \ | function` | — |
maxLength | number | -1 | Max characters (-1 = unlimited) |
showCharCount | boolean | false | Display character count |
saveInterval | number | 10000 | Auto-save idle delay in ms |
autoSaveOnIdle | boolean | false | Enable auto-save on idle |
enableHtmlEncode | boolean | false | Store/retrieve HTML as encoded string |
enableXhtml | boolean | false | XHTML validation mode |
enableHtmlSanitizer | boolean | true | XSS sanitization (disable only if you trust input) |
saveUrl | string | '' | Server URL to POST editor content |
<RichTextEditorComponent
value="<p>Hello</p>"
maxLength={1000}
showCharCount={true}
saveInterval={3000}
autoSaveOnIdle={true}
>
<Inject services={[Toolbar, HtmlEditor, Count]} />
</RichTextEditorComponent>---
Media Insert Properties
insertImageSettings: ImageSettingsModel
| Property | Default | Description |
|---|---|---|
allowedTypes | ['.jpeg','.jpg','.png'] | Permitted image formats |
display | 'inline' | 'inline' or 'block' |
saveFormat | SaveFormat | SaveFormat.Blob or SaveFormat.Base64 (enum) |
saveUrl | — | Upload endpoint URL |
removeUrl | — | Delete endpoint URL |
path | — | Base path for uploaded images |
resize | boolean | Allow image resize |
minWidth | `number \ | string` |
maxWidth | `number \ | string` |
minHeight | `number \ | string` |
maxHeight | `number \ | string` |
import { SaveFormat } from '@syncfusion/ej2-react-richtexteditor';
const insertImageSettings: ImageSettingsModel = {
saveUrl: 'url',
path: 'url',
allowedTypes: ['.jpeg', '.jpg', '.png', '.gif', '.webp'],
saveFormat: SaveFormat.Blob, // Use enum
resize: true,
minWidth: 20,
maxWidth: 1000
};insertVideoSettings: VideoSettingsModel
Similar to image settings with additional layoutOption ('Inline' or 'Break').
insertAudioSettings: AudioSettingsModel
Similar to video settings. Default maxFileSize: 30 MB.
fileManagerSettings: FileManagerSettingsModel
Configures a server-side file browser for image management. Key property: enable: true + ajaxSettings with API endpoints.
---
Font, Color & Format Properties
fontFamily: FontFamilyModel
const fontFamily: FontFamilyModel = {
default: 'Segoe UI',
width: '65px',
items: [
{ text: 'Segoe UI', value: 'Segoe UI' },
{ text: 'Arial', value: 'Arial' },
{ text: 'Courier New', value: 'Courier New, monospace' },
{ text: 'Georgia', value: 'Georgia, serif' }
]
};fontSize: FontSizeModel
const fontSize: FontSizeModel = {
default: '10pt',
width: '35px',
items: [
{ text: '8', value: '8pt' },
{ text: '10', value: '10pt' },
{ text: '12', value: '12pt' },
{ text: '14', value: '14pt' },
{ text: '18', value: '18pt' }
]
};fontColor: FontColorModel
Controls the font color palette. Key sub-properties: columns, modeSwitcher, showRecentColors, colorCode.
backgroundColor: BackgroundColorModel
Controls the text highlight color palette. Same structure as fontColor.
format: FormatModel
Defines paragraph format options (Paragraph, Heading 1–6, etc.).
lineHeight: LineHeightModel
Defines line-height options available in the toolbar dropdown.
numberFormatList: NumberFormatListModel
Defines ordered list style options (decimal, upper-roman, etc.).
bulletFormatList: BulletFormatListModel
Defines unordered list style options (disc, circle, square).
formatPainterSettings: FormatPainterSettingsModel
Controls which formats the Format Painter can copy/deny.
const formatPainterSettings: FormatPainterSettingsModel = {
allowedFormats: 'b; em; strong; span; p; div; h1; h2; h3;',
deniedFormats: null
};codeBlockSettings: CodeBlockSettingsModel
Configures languages available in the Code Block toolbar dropdown.
const codeBlockSettings: CodeBlockSettingsModel = {
defaultLanguage: 'javascript',
languages: [
{ language: 'javascript', label: 'JavaScript' },
{ language: 'typescript', label: 'TypeScript' },
{ language: 'python', label: 'Python' }
]
};Paste & Clipboard Properties
pasteCleanupSettings: PasteCleanupSettingsModel
| Property | Default | Description |
|---|---|---|
prompt | false | Show dialog asking how to paste |
plainText | false | Strip all formatting on paste |
keepFormat | true | Keep source formatting |
deniedTags | [] | HTML tags to strip (array of tag names) |
deniedAttrs | [] | Attributes to strip (array of attribute names) |
allowedStyleProps | [] | CSS properties to preserve (array of CSS property names) |
Security Best Practices: Always use deniedTags and deniedAttrs to prevent XSS attacks. Common dangerous elements to block:
const pasteCleanupSettings: PasteCleanupSettingsModel = {
prompt: true,
keepFormat: true,
// Security: Block dangerous tags
deniedTags: ['script', 'iframe', 'embed', 'object', 'applet'],
// Security: Strip potentially dangerous attributes
deniedAttrs: ['onerror', 'onload', 'onclick', 'onmouseover', 'style', 'class', 'id'],
// Allow only safe CSS properties
allowedStyleProps: ['color', 'font-size', 'font-weight', 'font-style', 'text-align', 'background-color']
};enableClipboardCleanup: boolean
When true, copy/cut operations remove unwanted inline styles. Default: true.
enableAutoUrl: boolean
When true, URLs are accepted as-is without prefixing https://. Default: false.
---
Table Properties
tableSettings: TableSettingsModel
| Property | Description |
|---|---|
width | Default table width |
minWidth | Minimum table width |
maxWidth | Maximum table width |
resize | Allow column/row resizing |
styles | Quick style presets |
---
AI Assistant Properties
aiAssistantSettings: AIAssistantSettingsModel
Configures the AI Assistant functionality in the Rich Text Editor. Allows customization of AI commands, popup appearance, toolbars, prompts, suggestions, and banner templates.
Type: AIAssistantSettingsModel
Default:
{
commands: DEFAULT_AI_COMMANDS,
popupWidth: '600px',
popupMaxHeight: '400px',
placeholder: 'Ask AI to rewrite or generate content.',
headerToolbarSettings: ['AIcommands', 'Close'],
promptToolbarSettings: ['Edit', 'Copy'],
responseToolbarSettings: ['Regenerate', 'Copy', '|', 'Insert'],
prompts: [],
suggestions: [],
bannerTemplate: '',
maxPromptHistory: 20
}| Property | Type | Default | Description |
|---|---|---|---|
commands | AICommands[] | Predefined commands | Defines AI command groups with text and prompt. Supports nested items for submenus |
popupWidth | `string \ | number` | '600px' |
popupMaxHeight | `string \ | number` | '400px' |
placeholder | string | 'Ask AI to rewrite or generate content.' | Placeholder text for the AI input textarea |
headerToolbarSettings | `(AssitantHeaderToolbarItems \ | IAIAssistantToolbarItem)[]` | ['AIcommands', 'Close'] |
promptToolbarSettings | `(AssistantPromptToolbarItems \ | IAIAssistantToolbarItem)[]` | ['Edit', 'Copy'] |
responseToolbarSettings | `(AssistantResponseToolbarItems \ | IAIAssistantToolbarItem)[]` | `['Regenerate', 'Copy', '\ |
prompts | PromptModel[] | [] | Defines predefined prompt-response pairs for preloading conversations |
suggestions | string[] | [] | Provides suggestion prompts to guide users |
bannerTemplate | `string \ | Function` | '' |
maxPromptHistory | number | 20 | Maximum number of prompts stored in history |
Toolbar Item Types:
- AssitantHeaderToolbarItems:
'Close' | 'AIcommands' | 'Clear' - AssistantPromptToolbarItems:
'Edit' | 'Copy' - AssistantResponseToolbarItems:
'Regenerate' | 'Copy' | 'Insert' | '|'
---
Custom AI Commands
Use the commands property to define custom AI command groups with nested items:
const aiAssistantSettings: AIAssistantSettingsModel = {
commands: [
{ text: 'Rewrite', prompt: 'Rewrite the content to be more refined.' },
{ text: 'Elaborate', prompt: 'Expand on the following content with more detail and explanation:' },
{
text: 'Change Tone',
items: [
{ text: 'Professional', prompt: 'Rewrite the following content in a professional tone:' },
{ text: 'Casual', prompt: 'Rewrite the following content in a casual, conversational tone:' },
{ text: 'Direct', prompt: 'Rewrite the following content to be more direct and to the point:' }
]
}
]
};
<RichTextEditorComponent aiAssistantSettings={aiAssistantSettings}>
<Inject services={[Toolbar, HtmlEditor, AIAssistant]} />
</RichTextEditorComponent>---
PromptModel Structure
For preloading conversations with prompt-response pairs:
interface PromptModel {
/**
* Specifies the prompt text.
* Represents the text used for prompting user input.
*/
prompt?: string;
/**
* Specifies the response associated with the prompt.
* Represents the text that provides the response to the prompt.
*/
response?: string;
/**
* Indicates if the response is considered helpful.
* Represents the state of whether the generated response is useful or not.
*/
isResponseHelpful?: boolean | null;
}⚠️ Important:
- All properties are optional in the TypeScript interface
- Use
promptproperty for the prompt text (NOTtext) - Use
responseproperty for preloaded AI responses isResponseHelpfultracks user feedback on AI responses
---
Preloading Prompts and Suggestions
const aiAssistantSettings: AIAssistantSettingsModel = {
// Preloaded prompt-response pairs (conversation history)
prompts: [
{
prompt: 'What is Essential Studio?',
response: 'Essential Studio is a software toolkit by Syncfusion that offers a variety of UI controls, frameworks, and libraries for developing applications on web, desktop, and mobile platforms.'
},
{
prompt: 'Summarize the key features',
response: 'Key features include comprehensive UI controls, cross-platform support, excellent performance, and extensive documentation.'
}
],
// Suggestion prompts (quick access buttons)
suggestions: [
'What are the popular components of Essential Studio?',
'Which web frameworks are supported by Essential Studio?',
'Explain the licensing model'
],
popupWidth: '700px',
popupMaxHeight: '500px',
maxPromptHistory: 15
};
<RichTextEditorComponent aiAssistantSettings={aiAssistantSettings}>
<Inject services={[Toolbar, HtmlEditor, AIAssistant]} />
</RichTextEditorComponent>---
Complete Configuration Example
import { RichTextEditorComponent, Inject, Toolbar, HtmlEditor, AIAssistant } from '@syncfusion/ej2-react-richtexteditor';
function App() {
const toolbarSettings: ToolbarSettingsModel = {
items: ['AICommands', 'AIQuery', '|', 'Bold', 'Italic', 'Underline']
};
const aiAssistantSettings: AIAssistantSettingsModel = {
// Popup dimensions
popupWidth: '650px',
popupMaxHeight: '450px',
placeholder: 'Ask AI to help with your content...',
// Custom AI commands with nested menus
commands: [
{ text: 'Rewrite', prompt: 'Rewrite the content to be more refined.' },
{ text: 'Elaborate', prompt: 'Expand on the following content:' },
{
text: 'Change Tone',
items: [
{ text: 'Professional', prompt: 'Make this professional:' },
{ text: 'Casual', prompt: 'Make this casual:' }
]
}
],
// Preloaded conversations
prompts: [
{
prompt: 'Summarize this document',
response: 'This document provides an overview of...'
}
],
// Quick suggestions
suggestions: ['Summarize', 'Fix grammar', 'Make shorter'],
// Toolbar customization
headerToolbarSettings: ['AIcommands', 'Clear', 'Close'],
promptToolbarSettings: ['Edit', 'Copy'],
responseToolbarSettings: ['Regenerate', 'Copy', '|', 'Insert'],
// History management
maxPromptHistory: 25
};
return (
<RichTextEditorComponent
toolbarSettings={toolbarSettings}
aiAssistantSettings={aiAssistantSettings}
>
<Inject services={[Toolbar, HtmlEditor, AIAssistant]} />
</RichTextEditorComponent>
);
}---
Handling AI Responses
See references/ai-assistant.md for complete documentation on:
- Handling streaming and non-streaming AI responses
- Using the
aiAssistantPromptRequestevent - Public methods:
executeAIPrompt,addAIPromptResponse,getAIPromptHistory,clearAIPromptHistory - Showing/hiding the AI Assistant popup programmatically
---
Slash Menu Properties
slashMenuSettings: SlashMenuSettingsModel
Configures the slash menu settings for the Rich Text Editor. This feature enables a quick-access popup menu triggered by typing /, allowing users to insert elements like headings, lists, media, and custom commands.
Type: SlashMenuSettingsModel
Default:
{
enable: false,
items: [
'Paragraph',
'Heading 1',
'Heading 2',
'Heading 3',
'Heading 4',
'OrderedList',
'UnorderedList',
'CodeBlock',
'Blockquote'
],
popupWidth: '300px',
popupHeight: '320px'
}| Property | Type | Default | Description |
|---|---|---|---|
enable | boolean | false | Specifies whether to enable or disable the slash menu in the editor |
items | `(SlashMenuItems \ | ISlashMenuItem)[]` | Built-in items |
popupWidth | `string \ | number` | '300px' |
popupHeight | `string \ | number` | '320px' |
Predefined SlashMenuItems:
'Heading 1' | 'Heading 2' | 'Heading 3' | 'Heading 4' |
'Paragraph' | 'Blockquote' | 'OrderedList' | 'UnorderedList' |
'Table' | 'Image' | 'Audio' | 'Video' |
'CodeBlock' | 'Emojipicker' | 'Link'⚠️ Common Mistakes:
- ❌ Use
'Emojipicker'NOT'Emojis'or'EmojiPicker' - ✅ Item names are case-sensitive and must match exactly
Custom Item Structure (ISlashMenuItem):
text: Display text of the menu itemcommand: Command to execute when selectediconCss: Icon CSS class for the menu itemdescription(optional): Additional information about the itemtype: Category/group of the menu item
Example:
const slashMenuSettings: SlashMenuSettingsModel = {
enable: true,
items: [
'Paragraph',
'Heading 1',
'Heading 2',
'OrderedList',
'UnorderedList',
'CodeBlock',
'Emojipicker', // Correct: 'Emojipicker' not 'Emojis'
'Image',
'Table',
'Link'
],
popupWidth: '400px',
popupHeight: '350px'
};
<RichTextEditorComponent slashMenuSettings={slashMenuSettings}>
<Inject services={[Toolbar, HtmlEditor, SlashMenu]} />
</RichTextEditorComponent>---
Import / Export Properties
importWord: ImportWordModel
const importWord: ImportWordModel = {
serviceUrl: 'url'
};exportWord: ExportWordModel
const exportWord: ExportWordModel = {
serviceUrl: 'url',
fileName: 'Document.docx',
stylesheet: null
};exportPdf: ExportPdfModel
const exportPdf: ExportPdfModel = {
serviceUrl: 'url',
fileName: 'Document.pdf',
stylesheet: null
};---
Miscellaneous Properties
| Property | Type | Default | Description |
|---|---|---|---|
undoRedoSteps | number | 30 | Number of undo/redo steps stored |
undoRedoTimer | number | 300 | Interval (ms) after which undo history clears |
enableMarkdownAutoFormat | boolean | true | Auto-convert Markdown syntax while typing |
slashMenuSettings | SlashMenuSettingsModel | — | Configure slash menu items |
emojiPickerSettings | EmojiSettingsModel | — | Configure emoji picker categories |
keyConfig | {[key: string]: string} | null | Override default keyboard shortcuts |
formatter | IFormatter | null | Custom formatter for key code actions |
Smart Editing Features in Syncfusion React Rich Text Editor
Table of Contents
Emoji Picker
Inject EmojiPicker and add 'EmojiPicker' to toolbar items. Opens a categorized emoji panel with a search box.
import {
HtmlEditor, Inject, Link, Image,
QuickToolbar, RichTextEditorComponent, Toolbar, EmojiPicker
} from '@syncfusion/ej2-react-richtexteditor';
const toolbarSettings: ToolbarSettingsModel = {
items: ['Bold', 'Italic', '|', 'EmojiPicker', '|', 'Undo', 'Redo']
};
function App() {
return (
<RichTextEditorComponent toolbarSettings={toolbarSettings}>
<Inject services={[Toolbar, HtmlEditor, EmojiPicker]} />
</RichTextEditorComponent>
);
}Customizing Emoji Sets
Override the default emoji categories and icons via emojiPickerSettings.iconsSet:
const emojiPickerSettings: EmojiSettingsModel = {
iconsSet: [
{
name: 'Smilies & People',
code: '1F600',
iconCss: 'e-emoji',
icons: [
{ code: '1F600', desc: 'Grinning face' },
{ code: '1F603', desc: 'Grinning face with big eyes' },
{ code: '1F604', desc: 'Grinning face with smiling eyes' },
{ code: '1F602', desc: 'Face with tears of joy' },
]
},
{
name: 'Animals & Nature',
code: '1F435',
iconCss: 'e-animals',
icons: [
{ code: '1F436', desc: 'Dog face' },
{ code: '1F431', desc: 'Cat face' },
{ code: '1F430', desc: 'Rabbit face' },
]
}
]
};
<RichTextEditorComponent
toolbarSettings={toolbarSettings}
emojiPickerSettings={emojiPickerSettings}
>
<Inject services={[Toolbar, HtmlEditor, EmojiPicker]} />
</RichTextEditorComponent>Slash Menu
Inject SlashMenu to enable a command menu triggered by typing / anywhere in the editor content. It shows a list of format/insertion actions the user can apply.
import { SlashMenu } from '@syncfusion/ej2-react-richtexteditor';
function App() {
return (
<RichTextEditorComponent>
<Inject services={[Toolbar, HtmlEditor, SlashMenu]} />
</RichTextEditorComponent>
);
}You can also add 'SlashMenu' to the toolbar items to trigger it via a button.
Customizing Slash Menu Items
Use slashMenuSettings.items to define which actions appear:
const slashMenuSettings: SlashMenuSettingsModel = {
enable: true,
items: [
'Paragraph', 'Heading 1', 'Heading 2', 'Heading 3',
'Heading 4', 'OrderedList', 'UnorderedList',
'CodeBlock', 'Blockquote', 'Link', 'Image', 'Video', 'Audio',
'Table', 'Emojis'
]
};
<RichTextEditorComponent slashMenuSettings={slashMenuSettings}>
<Inject services={[Toolbar, HtmlEditor, SlashMenu, Image, Link, Table, EmojiPicker]} />
</RichTextEditorComponent>Mentions
Inject the Mention module from @syncfusion/ej2-react-dropdowns to enable @mention functionality inside the editor. The mention component works alongside the RTE.
npm install @syncfusion/ej2-react-dropdownsimport { MentionComponent } from '@syncfusion/ej2-react-dropdowns';
import { RichTextEditorComponent, Inject, Toolbar, HtmlEditor } from '@syncfusion/ej2-react-richtexteditor';
const mentionData = [
{ name: 'Selma Rose', value: 'selma' },
{ name: 'Russo Kay', value: 'russo' },
{ name: 'Camden Kate', value: 'camden' },
];
function App() {
return (
<div>
<RichTextEditorComponent id="mention-rte" placeholder="Type @ to mention...">
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>
<MentionComponent
target="#mention-rte_rte-edit-view"
dataSource={mentionData}
fields={{ text: 'name', value: 'value' }}
popupWidth="250px"
itemTemplate='<span>${name}</span>'
displayTemplate='<span class="mention">@${name}</span>'
/>
</div>
);
}Target the RTE's editable area via #{rteId}_rte-edit-view.Mail Merge
Mail merge lets you insert dynamic field placeholders (like {{FirstName}}) into the editor content and later replace them with actual data values.
import { RichTextEditorComponent, Inject, Toolbar, HtmlEditor, QuickToolbar } from '@syncfusion/ej2-react-richtexteditor';
const toolbarSettings: ToolbarSettingsModel = {
items: ['Bold', 'Italic', '|', 'Undo', 'Redo']
};
// Example: Insert merge fields programmatically
function insertMergeField(rteRef: React.RefObject<RichTextEditorComponent>, field: string) {
rteRef.current?.executeCommand('insertHTML', `<span class="merge-field">{{${field}}}</span> `);
}
function App() {
const rteRef = useRef<RichTextEditorComponent>(null);
return (
<>
<button onClick={() => insertMergeField(rteRef, 'FirstName')}>Insert FirstName</button>
<button onClick={() => insertMergeField(rteRef, 'LastName')}>Insert LastName</button>
<RichTextEditorComponent ref={rteRef} toolbarSettings={toolbarSettings}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>
</>
);
}For dedicated mail merge support with a field picker UI, see docs/smart-editing/mail-merge.md in the documentation folder.
Styling & Customization in Syncfusion React Rich Text Editor
Table of Contents
- Theme Selection
- CSS Variable Customization
- Styling Editor Content Output
- Third-Party Integration
- Spell and Grammar Check
Theme Selection
Import the theme CSS files that match your app's design system. Replace tailwind3 with any available theme:
Available themes: material3, material3-dark, bootstrap5, bootstrap5-dark, fluent2, fluent2-dark, tailwind3, tailwind3-dark, fabric, highcontrast
/* src/App.css */
@import '../node_modules/@syncfusion/ej2-base/styles/material3.css';
@import '../node_modules/@syncfusion/ej2-buttons/styles/material3.css';
@import '../node_modules/@syncfusion/ej2-splitbuttons/styles/material3.css';
@import '../node_modules/@syncfusion/ej2-inputs/styles/material3.css';
@import '../node_modules/@syncfusion/ej2-lists/styles/material3.css';
@import '../node_modules/@syncfusion/ej2-navigations/styles/material3.css';
@import '../node_modules/@syncfusion/ej2-popups/styles/material3.css';
@import '../node_modules/@syncfusion/ej2-richtexteditor/styles/material3.css';CSS Variable Customization
Override built-in CSS variables to adjust colors, fonts, and sizes without changing the theme:
/* Override RTE primary accent color */
:root {
--color-sf-primary: #6200ee;
--color-sf-on-primary: #ffffff;
}
/* Customize toolbar height */
.e-richtexteditor .e-rte-toolbar {
min-height: 44px;
}
/* Customize editor content area font */
.e-richtexteditor .e-rte-content {
font-family: 'Georgia', serif;
font-size: 16px;
line-height: 1.6;
}Styling Editor Content Output
When you render the RTE's HTML value outside the editor (e.g., in a read-only preview), apply the e-rte-content class and include these styles so the output matches what users saw in the editor:
<div class="e-rte-content" dangerouslySetInnerHTML={{ __html: savedContent }} />/* Add to your global CSS */
.e-rte-content p { margin: 0 0 10px; }
.e-rte-content h1 { font-size: 2.17em; font-weight: 400; margin: 10px 0; }
.e-rte-content h2 { font-size: 1.74em; font-weight: 400; margin: 10px 0; }
.e-rte-content h3 { font-size: 1.31em; font-weight: 400; margin: 10px 0; }
.e-rte-content blockquote { border-left: solid 2px #333; padding-left: 5px; margin: 10px 0; }
.e-rte-content .e-rte-table { border-collapse: collapse; }
.e-rte-content .e-rte-table td, .e-rte-content .e-rte-table th {
border: 1px solid #bdbdbd; padding: 2px 5px; min-width: 20px;
}Tailwind CSS Preflight Conflict
If you're using Tailwind CSS and its preflight resets are overriding the RTE's styles, add a wrapper with @layer to scope the conflict:
/* Disable Tailwind preflight for RTE elements */
.e-richtexteditor, .e-rte-content {
/* Reset Tailwind's border-box and other base resets */
}Or exclude the RTE wrapper from Tailwind's preflight. See how-to.md for the full solution.
Third-Party Integration
CodeMirror (Enhanced Source Code Editor)
Replace the plain textarea source view with CodeMirror for syntax highlighting:
npm install codemirrorimport CodeMirror from 'codemirror';
import 'codemirror/mode/xml/xml';
import 'codemirror/lib/codemirror.css';
function App() {
const rteRef = useRef<RichTextEditorComponent>(null);
const sourceCodeChange = (args: SourceEventArgs) => {
if (args.mode === 'SourceCode') {
const srcView = (rteRef.current as any).element.querySelector('.e-rte-srctextarea');
const mirrorView = CodeMirror(srcView.parentNode, {
value: srcView.value,
lineNumbers: true,
mode: 'xml',
});
mirrorView.on('change', () => {
srcView.value = mirrorView.getValue();
});
}
};
return (
<RichTextEditorComponent ref={rteRef} actionBegin={sourceCodeChange}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>
);
}Spell and Grammar Check
Integrate browser-native spell checking or a third-party service:
Browser Native Spell Check
<RichTextEditorComponent>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>The RTE's contenteditable area inherits the browser's built-in spell checking. No additional configuration needed — the browser will underline misspelled words.
Custom Spell Check Integration
For full spell/grammar services (like LanguageTool or Grammarly), attach to the created event and initialize the third-party SDK on the editor's content area:
const onCreated = () => {
const editArea = (rteRef.current as any).contentModule.getEditPanel();
// Initialize your spell-check service on editArea
mySpellChecker.attach(editArea);
};
<RichTextEditorComponent ref={rteRef} created={onCreated}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>Toolbar Configuration in Syncfusion React Rich Text Editor
Table of Contents
Default Toolbar Items
When no toolbarSettings is provided, the editor shows a minimal default set. Always configure toolbarSettings.items explicitly to control what appears.
const toolbarSettings: ToolbarSettingsModel = {
items: [
'Bold', 'Italic', 'Underline', 'StrikeThrough',
'FontName', 'FontSize', 'FontColor', 'BackgroundColor',
'LowerCase', 'UpperCase', '|',
'Formats', 'Alignments', 'OrderedList', 'UnorderedList',
'Outdent', 'Indent', '|',
'CreateLink', 'Image', '|',
'ClearFormat', 'Print', 'SourceCode', 'FullScreen', '|',
'Undo', 'Redo'
]
};|inserts a vertical separator.-inserts a horizontal separator (MultiRow mode).
Toolbar Types
Set toolbarSettings.type to control how overflow items are handled.
Expand (default)
Hides overflowing items in a second row. Users click an arrow to reveal them. Best for compact layouts.
const toolbarSettings: ToolbarSettingsModel = {
type: 'Expand',
items: ['Bold', 'Italic', 'Underline', 'FontName', 'FontSize',
'FontColor', 'Formats', 'Alignments', 'OrderedList',
'UnorderedList', 'CreateLink', 'Image', 'Undo', 'Redo']
};
<RichTextEditorComponent toolbarSettings={toolbarSettings}>
<Inject services={[Toolbar, HtmlEditor, Link, Image]} />
</RichTextEditorComponent>MultiRow
Wraps all items across multiple rows. All items always visible — good for wide screens where every tool needs to be reachable.
const toolbarSettings: ToolbarSettingsModel = {
type: 'MultiRow',
items: ['Bold', 'Italic', 'Underline', 'FontName', 'FontSize',
'FontColor', 'Formats', 'Alignments', 'OrderedList',
'UnorderedList', 'CreateLink', 'Image', 'Undo', 'Redo']
};Scrollable
All items on a single line; the row scrolls horizontally when items overflow. Good when screen space is constrained and you want to avoid wrapping.
const toolbarSettings: ToolbarSettingsModel = {
type: 'Scrollable',
items: ['Bold', 'Italic', 'Underline', 'FontName', 'FontSize',
'CreateLink', 'Image', 'Undo', 'Redo']
};Toolbar Position
By default the toolbar sits at the top. Use toolbarSettings.position to move it to the bottom.
const toolbarSettings: ToolbarSettingsModel = {
position: 'Bottom',
items: ['Bold', 'Italic', 'Underline', 'CreateLink', 'Undo', 'Redo']
};For precise docs see: toolbar/toolbar-position.md
Sticky / Floating Toolbar
By default, the toolbar sticks to the top of the viewport while the user scrolls through long content. Control this with enableFloating and floatingToolbarOffset.
// Disable sticky toolbar
const toolbarSettings: ToolbarSettingsModel = {
enableFloating: false,
items: ['Bold', 'Italic', 'CreateLink', 'Undo', 'Redo']
};
// Adjust sticky toolbar offset (default 0)
<RichTextEditorComponent
toolbarSettings={toolbarSettings}
floatingToolbarOffset={60} // e.g., accommodate a 60px fixed header
>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>Toggle sticky toolbar dynamically:
function App() {
const rteRef = useRef<RichTextEditorComponent>(null);
const toggleFloating = (enabled: boolean) => {
if (rteRef.current) {
rteRef.current.toolbarSettings.enableFloating = enabled;
rteRef.current.dataBind(); // required to apply property change
}
};
return (
<>
<button onClick={() => toggleFloating(true)}>Enable Floating</button>
<button onClick={() => toggleFloating(false)}>Disable Floating</button>
<RichTextEditorComponent ref={rteRef} toolbarSettings={{ enableFloating: false, items: ['Bold', 'Italic'] }}>
<Inject services={[Toolbar, HtmlEditor]} />
</RichTextEditorComponent>
</>
);
}Quick Toolbar
The quick toolbar is a context-sensitive floating toolbar that appears when users click on specific content (images, links, tables). Inject QuickToolbar to enable it.
// Default quick toolbar items appear automatically for images and links
<RichTextEditorComponent>
<Inject services={[Toolbar, HtmlEditor, Image, Link, QuickToolbar]} />
</RichTextEditorComponent>Customizing Quick Toolbar Items
Use quickToolbarSettings to control which actions appear:
const quickToolbarSettings: QuickToolbarSettingsModel = {
image: [
'Replace', 'Align', 'Caption', 'Remove', 'InsertLink',
'OpenImageLink', '|', 'EditImageLink', 'RemoveImageLink',
'Display', 'AltText', 'Dimension'
],
link: ['Open', 'Edit', 'UnLink'],
table: [
'TableHeader', 'TableRows', 'TableColumns',
'TableCell', '|', 'BackgroundColor', 'TableRemove',
'TableCellVerticalAlign', 'Styles'
]
};
<RichTextEditorComponent quickToolbarSettings={quickToolbarSettings}>
<Inject services={[Toolbar, HtmlEditor, Image, Link, Table, QuickToolbar]} />
</RichTextEditorComponent>Related skills
How it compares
Choose this skill when you are committed to Syncfusion React; prefer a generic React form skill if you only need plain text or markdown without a commercial RTE.
FAQ
What is syncfusion-react-rich-text-editor?
syncfusion-react-rich-text-editor is an agent skill from syncfusion/react-ui-components-skills that helps developers integrate Syncfusion's React Rich Text Editor. Use it when adding WYSIWYG editing to React dashboards, CMS screens, or admin forms.
When should I use this Syncfusion RTE skill?
Reach for syncfusion-react-rich-text-editor when building React apps that already use Syncfusion and need formatted text input with toolbars. Skip it if you want a minimal markdown field or are not on the Syncfusion React stack.