Opinionated recipes for the most common editor setups—copy, paste, and adapt them to your stack knowing they already mirror the API guidance elsewhere in the docs.
Think of this page as your pattern library. Each scenario pairs runnable code with visual output so you can copy the parts you need—basic editors, restricted toolbars, plugin-heavy setups, form integrations, markdown previews, or themed embeds. Skim the headings to find a use case that resembles your app, then adapt the snippet knowing it already expresses best practices from the rest of the docs.
- Copy-first: Every code block is production-ready, including imports, hooks, and prop usage.
- Explained visuals: Result panes highlight what changed (toolbar, theme, behavior) so you understand the impact.
- Composable: Mix and match techniques—e.g., restricted tags plus custom styling—to tailor the editor to your product.
Basic Editor
Simple editor with default configuration:
Start here when you just need the default toolbar, full tag whitelist, and autosave enabled. The only required props are value and onChange; sizing props keep the demo tidy but are optional.
// Import React and the useState hook to manage component state
import React, { useState } from 'react';
// Import the Editor component from the package
import Editor from '@webbycrown/react-advanced-richtext-editor';
// Import the default stylesheet - required for proper editor appearance
import '@webbycrown/react-advanced-richtext-editor/dist/styles.css';
// Define a functional component for the basic editor example
function BasicEditor() {
// useState hook: Creates a state variable 'content' initialized to an empty string
// setContent is the function to update the content state
// This holds the HTML content that the editor produces
const [content, setContent] = useState('');
// Return the JSX for rendering
return (
<Editor
// Required prop: Current HTML content value (controlled component pattern)
value={content}
// Required prop: Callback function called whenever content changes
// Receives the new HTML string and updates our state via setContent
onChange={setContent}
// Optional prop: Sets the editor height to 400 pixels
height={400}
// Optional prop: Sets the editor width to 100% of parent container
width="100%"
/>
);
}Get started with the React Advanced Rich Text Editor in just a few lines of code.
Type rich text here and manage the HTML string in your React state.
This is a quick example showing the default editor with all features enabled.
All Tags Enabled
- Type rich text here and manage the HTML string in your React state. All formatting options are available.
- Full toolbar with all features: headings, formatting, alignment, links, images, tables, lists, colors, and more.
Use this baseline when scaffolding new pages. Layer on plugins, restricted tags, or custom styling from the other sections as requirements emerge.
Editor with Restricted Tags
Limit which HTML tags can be used:
Great for knowledge bases, email editors, or comment fields where only specific markup should survive. Combine allowedTags with custom plugins so users still have shortcuts for approved formatting.
// Import React and useState hook for state management
import React, { useState } from 'react';
// Import the Editor component
import Editor from '@webbycrown/react-advanced-richtext-editor';
// Import the required CSS styles
import '@webbycrown/react-advanced-richtext-editor/dist/styles.css';
// Component that demonstrates tag restriction for security/content control
function RestrictedEditor() {
// State to store the editor content (HTML string)
const [content, setContent] = useState('');
return (
<Editor
// Current HTML content value
value={content}
// Handler to update content state when user edits
onChange={setContent}
// Set fixed height for the editor
height={300}
// Make editor take full width of container
width="100%"
// CRITICAL: allowedTags prop restricts which HTML tags can be used
// Only tags in this array will be allowed - all others are stripped by DOMPurify
// This is essential for security (XSS prevention) and content control
allowedTags={[
'p', // Paragraphs
'h1', 'h2', 'h3', 'h4', 'h5', // Heading levels 1-5 (h6 excluded)
'strong', // Bold text
'em', // Italic text
'table', // Table container
'img', // Images
'thead', // Table header section
'tbody', // Table body section
'tr', // Table row
'th', // Table header cell
'td', // Table data cell
'br', // Line break
'u' // Underline text
]}
// Empty string disables localStorage auto-save functionality
// Content is only stored in React state, not persisted to browser storage
storageKey=""
/>
);
}Restricted Tags Only
Only the tags from your allowedTags array are available:
- Headings: H1, H2, H3, H4, H5
- Formatting: Bold (strong), Italic (em), Underline (u)
- Content: Paragraphs (p), Images (img), Tables (table, thead, tbody, tr, th, td)
- Other: Line breaks (br)
All other tags are automatically stripped via DOMPurify for security.
Pair allowedTags with DOMPurify config if you need attribute-level control (e.g., limiting <img> to certain hosts). This keeps storage and rendering pipelines aligned.
Editor with Custom Plugins
Add custom functionality with plugins:
Use plugins when you want bespoke toolbar buttons—snippets, mentions, asset pickers—without touching the editor internals. Keep the plugin array memoized if you compute it from props so React doesn’t re-render the toolbar unnecessarily.
// Import React and useState for component state
import React, { useState } from 'react';
// Import the Editor component
import Editor from '@webbycrown/react-advanced-richtext-editor';
// Import default editor styles
import '@webbycrown/react-advanced-richtext-editor/dist/styles.css';
// Import custom icons from react-icons library for plugin buttons
import { FaHighlighter, FaClock } from 'react-icons/fa';
// Component demonstrating how to add custom plugins/extensions
function CustomPluginEditor() {
// State to manage editor content
const [content, setContent] = useState('');
// Define custom plugins array - these add buttons to the toolbar
// Each plugin object defines a toolbar button with specific functionality
const customPlugins = [
{
name: "timestamp", // Unique identifier for the plugin
icon: <FaClock />, // React component to render as the button icon
title: "Insert Timestamp", // Tooltip text shown on hover
type: "timestamp" // Plugin type: "timestamp" is a built-in type that inserts current date/time
},
{
name: "highlight", // Unique identifier
icon: <FaHighlighter />, // Icon component for the button
title: "Highlight Text", // Tooltip description
tag: "mark" // Plugin type: "tag" wraps selected text with <mark> HTML tag
}
];
return (
<Editor
// Current HTML content
value={content}
// Content change handler
onChange={setContent}
// Pass the custom plugins array - they appear as buttons in the toolbar
// Plugins are inserted into the toolbar in the order defined in the array
plugins={customPlugins}
// Editor height
height={400}
/>
);
}Custom Plugins Integrated
Custom plugins are seamlessly integrated into the toolbar:
- Timestamp Plugin:
type: "timestamp"– Inserts current timestamp - Highlight Plugin:
tag: "mark"– Wraps selected text with <mark> tag
Plugins extend the toolbar in-place. You can add custom functionality, run commands, or integrate with APIs.
Mix plugin types: tag for semantic wrappers, type for built-ins like timestamps, and action for anything that needs custom logic or API calls.
Form Integration
Use the editor in a form:
Because the editor is controlled, it plugs into any form library. The sample shows vanilla state management, but the same pattern works with React Hook Form, Formik, or a headless CMS UI.
// Import React and useState hook
import React, { useState } from 'react';
// Import the Editor component
import Editor from '@webbycrown/react-advanced-richtext-editor';
// Import editor styles
import '@webbycrown/react-advanced-richtext-editor/dist/styles.css';
// Component demonstrating editor integration with a form
function FormWithEditor() {
// Single state object containing all form fields
// This pattern keeps related form data together
const [formData, setFormData] = useState({
title: '', // Regular text input value
message: '' // HTML content from the editor
});
// Reusable handler to update any field in formData
// Uses computed property name [field] to update the correct field
// prev => ({ ...prev, [field]: value }) merges new value with existing state
const handleEditorChange = (field, value) => {
setFormData(prev => ({
...prev, // Spread existing form data
[field]: value // Update only the specified field with new value
}));
};
// Form submission handler
const handleSubmit = (e) => {
e.preventDefault(); // Prevent default form submission (page reload)
console.log('Form Data:', formData); // Log or send to API
// In real app: submit formData to your backend API
};
return (
<form onSubmit={handleSubmit}>
{/* Standard text input field */}
<div>
<label>Title:</label>
<input
type="text"
value={formData.title} // Controlled input: value comes from state
onChange={(e) => setFormData(prev => ({
...prev,
title: e.target.value // Update title field on each keystroke
}))}
/>
</div>
{/* Rich text editor integrated as a form field */}
<div>
<label>Message:</label>
<Editor
// Use formData.message as the editor value
value={formData.message}
// When editor content changes, update the 'message' field in formData
// The editor's onChange passes the HTML string directly
onChange={(value) => handleEditorChange('message', value)}
height={300}
width="100%"
// Restrict allowed HTML tags for form content
allowedTags={[
'p', 'h1', 'h2', 'h3', // Paragraphs and headings
'strong', 'em', // Bold and italic
'table', 'img', // Tables and images
'ul', 'ol', 'li', // Lists (unordered, ordered, list items)
'br' // Line breaks
]}
// Disable auto-save since we're managing state in the form
storageKey=""
/>
</div>
{/* Submit button triggers handleSubmit */}
<button type="submit">Submit</button>
</form>
);
}🎉 We’re rolling out the advanced editor this week. Let us know what you build!
To keep validation snappy, treat the editor like any other field: store HTML in form state and derive preview/word counts client-side before submission.
Responsive Editor
Editor that adapts to screen size:
Set height/ width to "responsive" when embedding inside resizable panes (split views, modals). The editor stretches to whatever space its parent provides, making it ideal for dashboards.Code
// Import React and useState
import React, { useState } from 'react';
// Import the Editor component
import Editor from '@webbycrown/react-advanced-richtext-editor';
// Import default styles
import '@webbycrown/react-advanced-richtext-editor/dist/styles.css';
// Component demonstrating responsive/resizable editor behavior
function ResponsiveEditor() {
// State for editor content
const [content, setContent] = useState('');
return (
<Editor
// Current HTML content
value={content}
// Content update handler
onChange={setContent}
// "responsive" makes height adapt to parent container size
// Editor will grow/shrink based on available vertical space
height="responsive"
// "responsive" makes width fill 100% of parent container
// Editor adapts to container width changes (useful in resizeable panes)
width="responsive"
// Minimum height ensures editor remains usable even in very small containers
// Prevents editor from becoming too cramped on mobile/small screens
minHeight="200px"
/>
);
}Combine responsive sizing with minHeight to guarantee readability on compact devices while still filling large panes on desktop.
Editor with Custom Styling
Apply custom CSS classes:
Scoped classes are the fastest way to align the editor with your design system. Use them for gradients, spacing tweaks, or brand-specific typography without forking the core styles.
// Import React and useState
import React, { useState } from 'react';
// Import the Editor component
import Editor from '@webbycrown/react-advanced-richtext-editor';
// Import default editor styles (base styles)
import '@webbycrown/react-advanced-richtext-editor/dist/styles.css';
// Import your custom CSS file for additional styling
// This file will override or extend the default editor styles
import './custom-editor.css';
// Component showing how to apply custom styles via className
function CustomStyledEditor() {
// State for editor content
const [content, setContent] = useState('');
return (
<Editor
// className prop adds a custom CSS class to the editor root element
// This allows you to target and style specific editor instances
// All custom styles in custom-editor.css should be scoped under this class
className="my-custom-editor"
value={content}
onChange={setContent}
height={500}
/>
);
}Elevate the editor so it matches your product branding.
Use scoped CSS or CSS-in-JS to re-theme buttons, spacing, and typography.
CSS file (custom-editor.css):
// Target the toolbar within our custom editor class
// .rte-toolbar is the editor's toolbar container
.my-custom-editor .rte-toolbar {
// Apply a gradient background from blue to purple
background: #4caf50;
// Set text color to white for contrast
color: white;
// Round the top corners only (toolbar is at top)
border-radius: 8px 8px 0 0;
}
// Style individual toolbar buttons
// .rte-toolbar-button targets all buttons in the toolbar
.my-custom-editor .rte-toolbar-button {
color: white; // White icon/text color
}
// Hover state for toolbar buttons
// :hover pseudo-class applies styles when mouse is over button
.my-custom-editor .rte-toolbar-button:hover {
// Semi-transparent white background on hover for feedback
background: rgba(255, 255, 255, 0.2);
}
// Style the main editor content area
// .rte-editor-content is the editable content container
.my-custom-editor .rte-editor-content {
padding: 20px; // Add internal spacing around content
// Change font to Georgia serif for a more elegant look
font-family: 'Georgia', serif;
}Prefer CSS variables (see Theming docs) for palette changes and scoped classes for structural adjustments (padding, borders, layout), then mix both for full-control skins.
Editor Without Auto-Save
Disable localStorage auto-save:
Turn off persistence when drafts should only live server-side or when compliance rules forbid storing sensitive content in the browser. By setting storageKey="" you keep the editor fully controlled without background writes.
// Import React and useState hook
import React, { useState } from 'react';
// Import the Editor component
import Editor from '@webbycrown/react-advanced-richtext-editor';
// Import default editor styles
import '@webbycrown/react-advanced-richtext-editor/dist/styles.css';
// Component demonstrating editor without localStorage auto-save
// Use this when you want full control over when content is persisted
function NoAutoSaveEditor() {
// State to store editor content
// Since storageKey is empty, content only lives in this state
const [content, setContent] = useState('');
return (
<Editor
// Current HTML content value
value={content}
// Handler to update state when content changes
onChange={setContent}
// CRITICAL: Empty string disables localStorage auto-save
// By default, editor saves to localStorage using storageKey as the key
// Setting to "" means no automatic persistence - content only exists in React state
// Use this for: compliance, server-only storage, explicit save workflows
storageKey=""
height={400}
/>
);
}Use this when content should only persist after an explicit submit (e.g. workflow approvals).
The editor stays fully controlled by React — no localStorage writes occur. Combine with form libraries like React Hook Form where you already manage persistence.
Pair this with manual save buttons or form submissions so users explicitly choose when to persist data—ideal for approval flows or wizard steps.
Next.js Integration
Use in Next.js App Router:
The editor runs entirely on the client, so mark the file with 'use client' inside the App Router. For SSR/ISR pages, hydrate with an initial value fetched via loaders, then keep the component controlled on the client.
// CRITICAL: Next.js App Router directive
// 'use client' tells Next.js this component runs only on the client side
// Required because the editor uses browser APIs (localStorage, DOM manipulation)
// Without this, Next.js will try to render on the server and cause errors
'use client';
// Import useState hook (React import not needed in newer React versions)
import { useState } from 'react';
// Import the Editor component
import Editor from '@webbycrown/react-advanced-richtext-editor';
// Import editor styles - Next.js will handle CSS bundling
import '@webbycrown/react-advanced-richtext-editor/dist/styles.css';
// Export default component for Next.js page routing
// This component can be placed in app/ directory for App Router
export default function EditorPage() {
// State to manage editor content
// For SSR/ISR: Initialize from server-fetched data if needed
const [content, setContent] = useState('');
return (
<div className="container">
{/* Page title */}
<h1>My Editor</h1>
{/* Rich text editor component */}
<Editor
value={content}
onChange={setContent}
height={500}
/>
</div>
);
}Client Component ready: Drop the editor into App Router pages with 'use client'.
Tree-shakable styles: Import only dist/styles.css inside the component or layout where needed.
Supports SSR/ISR by hydrating on the client while keeping the value controlled via React state.
If you need to lazy-load the editor bundle in Next.js, wrap the import with dynamic(() => import(...), { ssr: false }) to keep server builds lean.