Examples

Updated 8 April 2026

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%"
    />
  );
}

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=""
    />
  );
}

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}
    />
  );
}

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>
  );
}

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 heightwidth 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}
    />
  );
}

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}
    />
  );
}

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>
  );
}

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.