Plugins

Updated 8 April 2026

Learn how the plugin registry works, where each button lives in the toolbar pipeline, and how to wire custom commands, actions, or React components without forking the core editor.

This section explains how to shape the toolbar around your product’s needs. Learn the four plugin archetypes, how to mix React icons with document commands, and how to run bespoke actions that inject HTML, data, or formatting. The examples and best practices below give you production-ready scaffolds plus guardrails for accessibility, error handling, and selection management.

Overview

The plugin system lets you compose the toolbar at runtime: pass an array of plugin objects and the editor renders them alongside the default formatting controls. Each plugin declares how it behaves (tag, command, or custom action), what UI it should render (icon + tooltip), and when it should be enabled (based on selection state).

  • Declarative API: Provide plain objects—no need to subclass or patch the editor. Hot reload friendly.
  • Toolbar integration: Plugins appear in deterministic slots so you can interleave them between default groups or render custom rows.
  • Execution flexibility: Trigger DOM commands, run arbitrary JavaScript, or reuse pre-built plugin types for common tasks.
  • Safety rails: When the editor is read-only or selection is empty, the plugin buttons automatically disable to prevent errors.

Plugin Types

1. HTML Tag Plugin

Wraps selected text with a custom HTML tag. This is ideal for semantic inline decorations (highlight, badge, custom spans) where you want predictable markup in the saved HTML string.

When to use: Apply consistent markup that your rendering pipeline or email templates already understand (e.g., wrap text in <mark> or <span class="mention">).

{
  name: "highlight",
  icon: <FaHighlighter />,
  title: "Highlight Text",
  tag: "mark"
}

Properties:

  • name: Unique identifier
  • icon: React component or string
  • title: Tooltip text
  • tag: HTML tag name (e.g., "mark""span""div")

The generated HTML still flows through DOMPurify sanitization. Make sure your tag is included in the whitelist if you need custom attributes or classes.

2. Command Plugin

Executes a document command (using document.execCommand). Think of this as a thin abstraction over the browser’s built-in formatting stack—perfect for headings, bold/italic toggles, or list insertion.

Limitations: Because execCommand is deprecated but still widely supported, always provide a graceful fallback (e.g., disable the button) for browsers that might drop support in the future. For deterministic output, consider the HTML Tag or Action plugin approach instead.

{
  name: "heading2",      // Unique plugin identifier
  icon: "H2",            // Button icon (text or React component)
  title: "Heading 2",    // Tooltip text
  cmd: "formatBlock",    // Document command to execute
  arg: "h2"              // Argument for the command
}

Available Commands:

  • formatBlock – Format block element (h1, h2, p, etc.)
  • bold – Make text bold
  • italic – Make text italic
  • underline – Underline text
  • strikeThrough – Strikethrough text
  • justifyLeft – Left align
  • justifyCenter – Center align
  • justifyRight – Right align
  • insertUnorderedList – Insert bullet list
  • insertOrderedList – Insert numbered list
  • createLink – Create link
  • removeFormat – Remove formatting

3. Action Plugin

Executes a custom JavaScript function. Action plugins unlock bespoke workflows: insert snippets fetched from an API, open modals, track analytics, or transform the current selection with your own logic.

Tip: Actions receive the editor instance so you can read the HTML value, focus the editor, or trigger selection helpers before injecting custom content.

{
  name: "timestamp",                    // Unique plugin identifier
  icon: <FaClock />,                  // React icon component
  title: "Insert Timestamp",            // Tooltip text
  action: (editor) => {                 // Custom function to execute
    const now = new Date();
    const timestamp = now.toLocaleString();
    document.execCommand("insertText", false, timestamp);  // Insert text at cursor
  }
}

4. Type Plugin

Uses built-in plugin types. These are prepackaged behaviors (timestamp, divider, lorem ipsum) that ship with the editor so you can enable common features without re-implementing them.

Extensibility: You can register your own types inside the editor configuration and then reference them by name across your app to keep plugin definitions DRY.

{
  name: "timestamp",      // Unique plugin identifier
  icon: <FaClock />,    // React icon component
  title: "Insert Time",   // Tooltip text
  type: "timestamp"       // Built-in plugin type
}

Available Types:

  • "timestamp" – Inserts current timestamp

Complete Examples

The following scenarios show how to bundle multiple plugin archetypes together, manage state, and style the toolbar so custom buttons feel native. Use them as blueprints for your own editor presets.

Example 1: Multiple Plugins

import React, { useState } from 'react';
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';
// Import React icons
import { FaHighlighter, FaClock, FaCode } from 'react-icons/fa';
// Define multiple custom plugins
const customPlugins = [
  {
    name: "timestamp",              // Plugin identifier
    icon: <FaClock />,           // Icon component
    title: "Insert Timestamp",      // Tooltip text
    action: (editor) => {           // Custom action function
      const now = new Date();
      document.execCommand("insertText", false, now.toLocaleString());
    }
  },
  {
    name: "highlight",              // Plugin identifier
    icon: <FaHighlighter />,    // Icon component
    title: "Highlight Text",        // Tooltip text
    tag: "mark"                     // Wrap selected text with <mark> tag
  },
  {
    name: "codeBlock",              // Plugin identifier
    icon: <FaCode />,           // Icon component
    title: "Code Block",            // Tooltip text
    action: (editor) => {           // Custom action to insert code block
      document.execCommand("insertHTML", false, '<pre><code></code></pre>');
    }
  }
];

function MyEditor() {
  // Store HTML content in state
  const [content, setContent] = useState('');

  return (
    <Editor
      value={content}           // Current HTML content
      onChange={setContent}     // Update state when content changes
      plugins={customPlugins}   // Add custom plugins to toolbar
      height={400}              // Editor height in pixels
    />
  );
}

This configuration mixes one action plugin, one tag plugin, and one action that injects HTML. Because plugins are plain objects, you can source them from JSON, feature flags, or user-specific toolsets.

Example 2: Custom Styling Plugin

Demonstrates how to reach into the DOM selection, wrap it with styled markup, and keep the experience accessible by falling back when no text is highlighted.

import React, { useState } from 'react';
import Editor from '@webbycrown/react-advanced-richtext-editor'; // Import the default bundle
// Import the default stylesheet - required for proper editor appearance
import '@webbycrown/react-advanced-richtext-editor/dist/styles.css';

const customStylePlugin = { // Custom style plugin
  name: "customStyle", // Plugin identifier
  icon: "🎨", // Icon component
  title: "Custom Style", // Tooltip text
  action: (editor) => { // Custom action to apply custom style
    const selection = window.getSelection(); // Get selected text
    if (selection.rangeCount > 0) {
      const range = selection.getRangeAt(0); // Get selected text range
      const span = document.createElement('span');
      span.style.color = '#ff0000';
      span.style.fontWeight = 'bold';
      span.textContent = selection.toString();
      range.deleteContents();
      range.insertNode(span);
    }
  }
};

function CustomStyledEditor() { 
  const [content, setContent] = useState(''); // Store HTML content in state

  return (
    <Editor
      value={content}
      onChange={setContent}
      plugins={[customStylePlugin]} // Add custom style plugin to toolbar
      height={400}
    />
  );
}

Plugin Best Practices

  1. Unique Names: Always use unique plugin names to avoid conflicts. Names double as analytics keys and React list keys, so duplicates can cause rendering bugs.
  2. Accessible Icons: Use meaningful icons that users can understand and pair them with title text so screen readers announce the action.
  3. Descriptive Titles: Provide clear tooltip text plus optional hotkey hints (e.g., “Highlight (Ctrl+Shift+H)”) to improve discoverability.
  4. Error Handling: Wrap actions in try/catch blocks, especially when hitting APIs or manipulating the DOM. If something fails, surface a toast and leave the selection untouched.
  5. Selection Handling: Check if text is selected before applying formatting. Disable the button when nothing is highlighted to prevent confusing no-ops.
  6. Undo/Redo Safety: Fire actions through document.execCommand or use the editor’s mutation helpers so the browser history stack stays intact.

Troubleshooting

Most plugin issues trace back to missing props, stale selections, or sanitization filters. Use the checklist below when something doesn’t behave as expected.

Plugin Not Appearing

  • Check that the plugin array is properly passed to the plugins prop and that you are not mutating it in place (React needs a new array reference).
  • Verify that each plugin object has required properties (nameicontitle). Missing names are silently ignored to prevent toolbar crashes.
  • Inspect browser console for prop-type warnings or sanitization errors indicating that a tag/attribute was stripped.

Plugin Not Working

  • Ensure the action function is properly defined and bound. Arrow functions are recommended to keep this scope predictable.
  • Check that document commands are supported in your browser; Safari Tech Preview occasionally disables certain execCommand calls.
  • Verify selection handling in action plugins. Remember to call editor.focus() before injecting HTML if your action opens a modal first.
  • Confirm the generated markup survives sanitization—if you inject custom attributes, extend the whitelist accordingly.