npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-text-editor-kit

v4.2.0

Published

React Text Editor Kit is a customizable rich text editor component for React applications. It provides a flexible and easy-to-use interface for users to create and edit content with various formatting options. And also easy to integrate in react applicati

Readme

✨ React Editor Kit (react-text-editor-kit)

[!IMPORTANT] 🔑 API Key Required: An apiKey is required to use React Editor Kit. Please visit https://reacteditor.metadevzone.com/ to log in / sign up and create your API key. Pass it to <ReactEditorKit apiKey="YOUR_API_KEY" /> to activate the editor canvas and all its features.


📖 Table of Contents


🔑 Getting Your API Key (Required)

To use React Editor Kit, providing an apiKey is mandatory. Without a valid API key, the editor controls and editing canvas will remain disabled.

Quick Setup Steps:

  1. Visit https://reacteditor.metadevzone.com/
  2. Log in or sign up for a developer account.
  3. Generate your API Key from the dashboard.
  4. Pass the API key to <ReactEditorKit apiKey="your_api_key_here" />.
<ReactEditorKit
  apiKey="your_api_key_here"
  value={content}
  onChange={setContent}
/>

✨ Key Highlights & Super-Features

┌────────────────────────────────────────────────────────────────────────────────────────┐
│                                   REACT EDITOR KIT                                     │
├────────────────────────────────────────────────────────────────────────────────────────┤
│  ⚡ Zero Lag Typing    │  📊 Next-Gen Tables      │  🔍 Draggable Find & Replace       │
│  ✍️ Offline Spellcheck │  🖼️ Live Image Cropper   │  🛡️ XSS Script Sanitizer          │
│  🎨 Dynamic Theming   │  🎛️ Modular Toolbars     │  🖱️ Precision Right-Click Menu     │
└────────────────────────────────────────────────────────────────────────────────────────┘

1. 📊 Advanced Isolated Table Suite

Edit complex tables intuitively without messing up layout or adjacent cells.

┌─────────────────────────────────────────────────────────────────────────────────────┐
│ 📑 Duplicate Row  │  🗑️ Delete Row  │  ➕ Insert Column   │  ⚙️ Table Props           │
└─────────────────────────────────────────────────────────────────────────────────────┘
  • Visual 10x10 Table Grid Picker: Hover and click to instantly insert tables of any dimension.
  • Dynamic Quick-Action Bar: Floating toolbar above active tables for instant one-click modifications.
  • Precision Table Operations:
    • Insert row above / below, duplicate row, delete row.
    • Insert column before / after, duplicate column, delete column.
    • Granular cell merging (colspan) and cell splitting.
  • Custom Cell & Table Properties: Customize cell background colors, borders, paddings, alignments, widths, and heights via dedicated modal dialogs.
  • Isolated Typing Engine: Cell contents maintain isolated line wraps without shifting adjacent cell proportions.
  • Keyboard Gliding: Seamlessly navigate between table cells using Tab and Shift + Tab. Pressing Tab in the last cell automatically creates and moves to a fresh new row!

2. 🔍 Floating & Draggable Find & Replace

A zero-obstruction find and replace utility designed for frictionless editing in long documents.

  • Floating & Draggable Canvas: Floats smoothly on the canvas and can be dragged anywhere so your content remains 100% visible.
  • Multi-Element Search: Deep scans paragraphs, headings (H1–H6), blockquotes, lists, and nested table cells.
  • Smart Search Options:
    • Aa Match Case: Case-sensitive search.
    • \b Match Whole Word: Word-boundary regex matching.
  • Real-Time Match Counter: Live match badge (e.g. 4 of 18 matches).
  • Interactive Navigation: Step through matches forward (Enter / Next) and backward (Shift+Enter / Prev).
  • Single & Batch Replace: Instant active match replacement or 1-click Replace All.

3. ✍️ Offline In-Memory Spell Checker & Suggestions

Operates 100% client-side with zero network requests, zero API latency, and complete privacy.

  • 50,000+ Word In-Memory Dictionary: High-performance Trie / hash-set dictionary for instantaneous lookups.
  • Morphology & Grammar Engine: Intelligently handles plurals (-ies ➔ -y, -es), past tense (-ed), continuous tense (-ing), adverbs (-ly), and common prefixes (un-, re-, multi-, pre-).
  • Typo Highlighting: Non-destructive red wavy underlines (span.mlx-spell-error).
  • Ranked Suggestion Popover: Click any misspelled word to inspect suggestions ranked by Levenshtein edit distance.
  • ➕ Custom User Dictionary: Add proprietary terms, product names, or acronyms directly to localStorage.
  • 🧼 100% Clean Output: All spell check markers are automatically stripped before triggering onChange.

4. 🖼️ Media Management, Image Cropping & 8-Point Resizing

  • Multi-Source Images: Support for direct image file uploads or remote image URLs.
  • Interactive Image Cropper: Built-in crop modal powered by react-image-crop for cropping and aspect ratio adjustments before insertion.
  • 8-Point Interactive Resizing: Click any image to reveal 8 responsive resize handles for intuitive proportional scaling.
  • Video & Media Embeds: Embed YouTube, Vimeo, Dailymotion, MP4 videos, and responsive iframes with custom dimension controls.

5. 🛡️ Built-in Security & Safe Sandboxed Renderer

  • Script Sanitizer Engine (ScriptSanitizer): Scans HTML for malicious scripts, cookie theft attempts (document.cookie), storage scraping (localStorage), unauthorized fetches, eval(), dangerous pseudo-protocols (javascript:), and disarms malicious inline handlers (onclick, onerror).
  • <SafeSandboxedRenderer /> Component: Render saved editor content in an isolated iframe with an automatic height synchronization message bus and optional security status badge.

6. 🖱️ Context Menu (Right-Click Suite)

  • Context-Aware Actions: Right-click anywhere in the editor to open a tailored context menu at exact mouse coordinates.
  • Fast Table Controls: Quick access to duplicate/delete rows, column tools, cell properties, and table deletion.
  • Link & Image Controls: Edit hyperlinks, unlink, open links in new tabs, or inspect image properties.

7. ✅ Checklist, Strikethrough, Emoji Picker & Word Count

New editor tools for task lists, text decoration, emoji insertion, and live writing stats.

  • Checklist (checklist): Insert an interactive todo list. Click the checkbox to mark an item done (checked state is preserved in HTML via mlx-checklist-checked / data-checked="true" and also renders in <SafeSandboxedRenderer />).
  • Strikethrough (strikethrough): Toggle line-through formatting on the selected text from the toolbar or Format menu.
  • Emoji Picker (emoticons): Searchable emoji dialog with categories (Smileys, Gestures, Hearts, Objects). Search by name or keyword (e.g. smile, heart, fire).
  • Word / Character Count (enable_word_count): Live status bar under the canvas showing accurate word and character totals. List and checklist items are counted as separate blocks so items are not merged into one word.
<ReactEditorKit
  apiKey="your_api_key_here"
  value={content}
  onChange={setContent}
  enable_word_count={true}
  toolbar={[
    "bold",
    "italic",
    "underline",
    "strikethrough",
    "|",
    "orderedList",
    "unorderedList",
    "checklist",
    "|",
    "emoticons",
  ]}
/>

📦 Installation

Install via npm, yarn, or pnpm:

# Using npm
npm install react-text-editor-kit

# Using yarn
yarn add react-text-editor-kit

# Using pnpm
pnpm add react-text-editor-kit

Peer Dependencies

Ensure your project has React 18+ installed:

npm install react@^18.0.0 react-dom@^18.0.0

🚀 Quick Start Guide

Basic Controlled Example

import React, { useState } from "react";
import ReactEditorKit from "react-text-editor-kit";

export default function MyEditorPage() {
  const [content, setContent] = useState(
    "<h2>Welcome to React Editor Kit</h2><p>Start writing beautiful articles...</p>",
  );

  return (
    <div style={{ maxWidth: "1000px", margin: "40px auto", padding: "0 20px" }}>
      <ReactEditorKit
        apiKey="your_api_key_here" // Required: Get free key at https://reacteditor.metadevzone.com/
        value={content}
        onChange={(cleanHtml) => setContent(cleanHtml)}
        placeholder="Type your story here..."
        height="450px"
        enable_spell_check={true}
      />
    </div>
  );
}

⚙️ Props & Configuration Reference

Here is the complete, comprehensive list of all props accepted by <ReactEditorKit />:

| Prop Name | Type | Default | Description | | :-------------------- | :-----------------------------------------------------------: | :---------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | value | string | "" | Controlled HTML string passed to the editor canvas. | | onChange | (cleanHtml: string) => void | undefined | Callback fired whenever content changes. Returns purified, sanitized HTML with all temporary markers (spellcheck spans, find/replace marks, selection bookmarks) removed. | | placeholder | string | "Please Write Something..." | Placeholder text displayed when the editor canvas is empty. | | height | string | "auto" | CSS height for the editor container (e.g. "450px", "70vh", "100%"). | | enable_spell_check | boolean | false | Enables the in-memory offline spell checker, grammar morphology engine, red wavy underlines, and interactive typo suggestion popup. | | enable_word_count | boolean | true | Shows a live words / characters status bar under the editor. Counts list and checklist items as separate blocks. Set to false to hide the status bar. | | toolbar | Array<string \| object> | TOOLBAR_ITEMS | Custom list of toolbar items, buttons, and separator dividers ("\|"). | | navbar | Array<string \| object> | NAVBAR_ITEMS | Custom list of top menu navbar options (e.g., ["file", "view", "insert", "format"]). | | remove_from_toolbar | string[] | [] | Array of item names to exclude from the toolbar (e.g. ["video", "source_code"]). | | remove_from_navbar | string[] | [] | Array of item names to exclude from the top navbar menu. | | theme_config | Record<string, string> | {} | Custom theme styling map targeting internal CSS variables (e.g., background color, borders, text color, button hover states). | | image_handler | (inputs: object, item: object) => Promise<string> \| string | undefined | Custom async callback to handle image uploads to your own cloud storage (AWS S3, Cloudinary, Firebase, etc.). Must return the uploaded image URL string. Defaults to Base64 FileReader data URLs. | | getEditorRef | (ref: React.RefObject<HTMLDivElement>) => void | undefined | Callback returning the editorRef to directly access the contentEditable DOM element. | | mainProps | React.HTMLAttributes<HTMLDivElement> | {} | HTML attributes passed directly to the outer editor wrapper element (e.g. className, id, data-*). | | style | React.CSSProperties | {} | Inline styles applied directly to the inner contentEditable editing canvas. | | apiKey | string (Required) | "" | Required. Your API key obtained from reacteditor.metadevzone.com. Required to activate the editor canvas and enable full editing functionality. | | sanitizeOptions | object | undefined | Restricts which scripts / iframes survive sanitizing (by default any embed code is kept). See Embed Code & Script Allowlist. | | allowedScriptDomains| string[] | undefined | Shortcut for sanitizeOptions.allowedScriptDomains, e.g. ["cdn.oncehub.com"] (only these + built-in CDNs). | | pasteHtmlFromText | boolean \| "ask" | true | When plain text that is HTML/embed code is pasted, insert it as HTML instead of escaped text. "ask" shows a confirm dialog, false always pastes text. | | ...others | any | — | All remaining props (e.g. aria-*, onFocus, onBlur, tabIndex) are spread onto the inner contentEditable element. |


🎨 Custom Theming & Dark Mode

You can completely customize the visual theme using the theme_config prop. The keys map directly to CSS custom properties:

import React, { useState } from "react";
import ReactEditorKit from "react-text-editor-kit";

export default function DarkModeEditor() {
  const [content, setContent] = useState("<p>Sleek Dark Mode Content</p>");

  const darkTheme = {
    "background-color": "#1e1e2e",
    "border-color": "#313244",
    "text-color": "#cdd6f4",
    "toolbar-button-background": "#1e1e2e",
    "toolbar-text-color": "#cdd6f4",
    "toolbar-button-hover-background": "#313244",
    "toolbar-button-selected-background": "#45475a",
    "svg-color": "#cdd6f4",
    "save-button-background": "#a6e3a1",
  };

  return (
    <ReactEditorKit
      apiKey="your_api_key_here"
      value={content}
      onChange={setContent}
      theme_config={darkTheme}
      height="500px"
    />
  );
}

Available theme_config Keys:

| Key | Default Value | Target Element / Purpose | | :----------------------------------- | :---------------: | :---------------------------------------------------- | | background-color | #ffffff | Editor canvas & dropdown container background | | border-color | #eeeeee | Toolbar dividers, modal borders, and canvas outlines | | text-color | #414141 | Content editable canvas typography & modal text | | toolbar-button-background | #ffffff | Toolbar button default background color | | toolbar-text-color | #414141 | Toolbar button typography and label colors | | toolbar-button-hover-background | #efefef | Hover state background on toolbar buttons & dropdowns | | toolbar-button-selected-background | #dee0e2 | Active/selected state background for toolbar buttons | | svg-color | #414141 | Icon fill and stroke color in toolbar and modals | | save-button-background | rgb(9, 134, 62) | Primary action buttons inside modals (Save / Insert) |


🎛️ Toolbar & Navbar Customization

You have full control over what appears in both the top Navbar and the main Toolbar.

Default Toolbar Items

The default toolbar keeps only the everyday buttons so it fits small screens:

[
  "undo", "redo", "|",
  "format", "fontsize", "|",
  "bold", "italic", "underline", "|",
  "alignment", "|",
  "orderedList", "unorderedList", "|",
  "textColor", "backgroundColor", "|",
  "link", "image", "video", "|",
  "removeFormat", "source_code", "full_screen",
]

Strikethrough, superscript, subscript, fonts, tables, checklists, special characters, emoji, horizontal lines, find & replace, preview and print are in the File / View / Insert / Format menus.

All Toolbar Items

Pass any of these in the toolbar prop to show more buttons, e.g. the full toolbar of earlier versions:

[
  "undo", "redo", "|",
  "format", "fontfamily", "fontsize", "lineHeight", "|",
  "bold", "italic", "underline", "strikethrough", "superscript", "subscript", "|",
  "alignment", "|",
  "indent", "outdent", "|",
  "orderedList", "unorderedList", "checklist", "|",
  "removeFormat", "|",
  "textColor", "backgroundColor", "|",
  "ltr", "rtl", "|",
  "copy", "cut", "paste", "select_all", "find_replace", "spellcheck", "|",
  "image", "link", "video", "|",
  "source_code", "full_screen", "special_character", "emoticons", "horizontal_line",
]

Default Navbar Items

The default NAVBAR_ITEMS array is only the menus:

["file", "view", "insert", "format"]

Buttons such as "select_all", "find_replace", "image", "link", "video", "copy", "cut", "paste" and "|" can be added to the navbar prop as well.

  • file menu options: new_document, preview, print
  • view menu options: source_code, full_screen, find_replace, spellcheck
  • insert menu options: table, image, link, video, hr_line, special_char, checklist, emoticons
  • format menu options: bold, italic, underline, strikethrough, superscript, subscript, font, font_size, alignment

Excluding Tools

To easily remove specific tools without rewriting the whole toolbar array, pass remove_from_toolbar or remove_from_navbar:

<ReactEditorKit
  apiKey="your_api_key_here"
  value={content}
  onChange={setContent}
  remove_from_toolbar={["video", "ltr", "rtl", "source_code"]}
  remove_from_navbar={["video"]}
/>

Custom Minimal Toolbar

<ReactEditorKit
  apiKey="your_api_key_here"
  value={content}
  onChange={setContent}
  toolbar={[
    "bold",
    "italic",
    "underline",
    "|",
    "fontsize",
    "textColor",
    "|",
    "alignment",
    "orderedList",
    "unorderedList",
    "|",
    "link",
    "image",
  ]}
  navbar={[]} // Disables top menu navbar
/>

☁️ Custom Cloud Image Upload Handler (image_handler)

By default, uploaded images are encoded as Base64 data URLs. If you want to upload images to AWS S3, Cloudinary, Firebase Storage, or your backend server, provide an async image_handler function:

import React, { useState } from "react";
import ReactEditorKit from "react-text-editor-kit";

export default function CloudUploadEditor() {
  const [content, setContent] = useState("");

  const handleCloudImageUpload = async (inputs, item) => {
    // inputs.image is the raw File object from the user's computer
    // inputs.type indicates 'upload' or 'general' (URL)
    const file = inputs.image;
    if (!file) return null;

    const formData = new FormData();
    formData.append("file", file);
    formData.append("upload_preset", "your_cloudinary_preset");

    try {
      const response = await fetch(
        "https://api.cloudinary.com/v1_1/your_cloud_name/image/upload",
        {
          method: "POST",
          body: formData,
        },
      );
      const data = await response.json();
      // Return the public secure URL of the uploaded image
      return data.secure_url;
    } catch (error) {
      console.error("Cloud upload failed:", error);
      return null;
    }
  };

  return (
    <ReactEditorKit
      apiKey="your_api_key_here"
      value={content}
      onChange={setContent}
      image_handler={handleCloudImageUpload}
      height="450px"
    />
  );
}

🧩 Embed Code & Script Allowlist (sanitizeOptions)

Any embed code works out of the box: booking calendars (OnceHub / ScheduleOnce, Calendly), forms (JotForm, HubSpot, Typeform), chat widgets, social posts, etc. Inside the editor, scripts from any http(s) host and inline scripts are kept (javascript: / data: script URLs, <object> / <embed>, srcdoc iframes and malicious inline event handlers are still removed).

To restrict what editors may add, pass sanitizeOptions:

<ReactEditorKit
  value={value}
  onChange={setValue}
  apiKey="YOUR_API_KEY"
  sanitizeOptions={{
    allowedScriptDomains: ["cdn.oncehub.com", "*.calendly.com"],
    allowInlineScripts: "heuristic",
    onSanitize: ({ removedCount, violations }) => console.warn(violations),
  }}
/>

| Option | Type | Default | Description | | :---------------------------- | :-------------------: | :-----------: | :----------------------------------------------------------------------------------------------------------------------- | | allowedScriptDomains | string[] \| "*" | "*" | "*" keeps scripts from any http(s) host. An array keeps only the built-in list plus these hosts. The built-in list covers common embed providers: scheduling (OnceHub, Calendly, Acuity, GoHighLevel), video (Vimeo, YouTube, Wistia, Loom, Vidyard), forms and email (Typeform, JotForm, HubSpot, Tally, ClickFunnels, ConvertKit, Mailchimp, ActiveCampaign), social (X/Twitter, Instagram, Facebook, TikTok, LinkedIn, Pinterest), chat (Tawk, Crisp, Intercom, Tidio, Zendesk), Stripe, PayPal, Gumroad, Eventbrite, Trustpilot, Elfsight and common CDNs (ALLOWED_EXTERNAL_CDNS). Accepts host, *.domain.com (domain + subdomains) or a full URL. | | replaceDefaultScriptDomains | boolean | false | With an allowedScriptDomains array: drop the built-in CDN list. | | allowedIframeDomains | string[] \| "*" | "*" | "*" keeps any http(s) iframe. An array keeps only iframes from those hosts. | | allowInlineScripts | boolean \| "heuristic" | true | true keeps all inline scripts. "heuristic" keeps only those that do not touch cookies, storage, network, eval, etc. false removes all. | | keepComments | boolean | false | Keep HTML comments when pasting rich HTML (e.g. from Word). Embed code pasted as text and the Source Code view always keep comments. | | disabled | boolean | false | Trust all content (only javascript: / vbscript: URLs are still removed). | | onSanitize | function | undefined | Called with { removedCount, violations } whenever incoming content (value, source view, paste, embed dialog) was changed. |

The standalone sanitizeDangerousScripts() helper and <SafeSandboxedRenderer /> keep their stricter defaults (only the built-in provider list, heuristic inline scripts).

Embed code can be added from the Source Code view, the Insert Video → Embed tab, or by pasting it as plain text (pasteHtmlFromText, on by default). Inside the editor the whole embed (the <script> plus its comments and widget elements such as <div data-so-page>) is shown as one non-editable </> Embed code block (<div data-embed-script="…">), so a widget script running elsewhere on the page cannot change it, and onChange, the Source Code view and Preview output the embed code exactly as it was added. Content saved with these placeholders by older versions is output as the original scripts as well. The editor never runs these scripts; the page that renders the saved HTML must execute them.

HTML saved from the Source Code view (or passed as value) is output exactly as typed, with the same line breaks, attribute layout and comments, as long as it is not changed in the visual editor and nothing had to be removed by the sanitizer. Reopening the Source Code view shows that same text. After a visual edit the content is output in the browser's normalized HTML form.


🛡️ Safe Content Rendering (SafeSandboxedRenderer)

When displaying user-generated rich HTML on public web pages, you must protect your application from XSS attacks. react-text-editor-kit provides a built-in <SafeSandboxedRenderer /> component:

import React from "react";
import { SafeSandboxedRenderer } from "react-text-editor-kit";

export default function ArticlePreview({ articleHtml }) {
  return (
    <div style={{ maxWidth: "800px", margin: "0 auto" }}>
      <h2>Article Preview</h2>
      <SafeSandboxedRenderer
        htmlContent={articleHtml}
        showSecurityBadge={true} // Displays a subtle security indicator
        style={{ borderRadius: "12px", border: "1px solid #e2e8f0" }}
      />
    </div>
  );
}

<SafeSandboxedRenderer /> Props

| Prop Name | Type | Default | Description | | :------------------ | :-------------------: | :-----: | :----------------------------------------------------------------------------- | | htmlContent | string | "" | Raw HTML content to be sanitized and rendered. | | showSecurityBadge | boolean | true | Shows a top status bar indicating active sandboxing and blocked scripts count. | | className | string | "" | CSS class name applied to the container wrapper. | | style | React.CSSProperties | {} | Inline CSS styling applied to the outer container. |


⚡ Remote Backend Functions Integration (useBackendFunctions)

For advanced SaaS platforms, react-text-editor-kit includes hooks to dynamically fetch and execute server-side business logic and custom editor functions:

import { useBackendFunctions, useBackendFunction } from "react-text-editor-kit";

function CustomPluginComponent({ apiKey }) {
  const { functions, isLoading, executeFunction, hasFunction } =
    useBackendFunctions(apiKey, "https://api.yourdomain.com/editor/plugins");

  const handleCustomAction = () => {
    if (hasFunction("formatLegalDocument")) {
      const result = executeFunction("formatLegalDocument", {
        jurisdiction: "US",
      });
      console.log("Plugin executed:", result);
    }
  };

  return (
    <button onClick={handleCustomAction} disabled={isLoading}>
      Run Legal Formatter
    </button>
  );
}

⌨️ Keyboard Shortcuts

| Shortcut | Action | Scope | | :---------------------------------------------- | :---------------------------------------------------- | :-------- | | Ctrl / Cmd + B | Toggle Bold formatting | Selection | | Ctrl / Cmd + I | Toggle Italic formatting | Selection | | Ctrl / Cmd + U | Toggle Underline | Selection | | Ctrl / Cmd + F | Open floating Find & Replace | Global | | Ctrl / Cmd + Z | Undo last action | History | | Ctrl / Cmd + Y | Redo last action | History | | Tab | Jump to next table cell (Adds row if on last cell) | Tables | | Shift + Tab | Jump to previous table cell | Tables | | Backspace / Delete | Remove active image / Merge empty list items & blocks | Canvas | | Esc | Close active modal / Find & Replace / Popovers | Dialogs |


🧼 Clean HTML Output Guarantee

Unlike many traditional editors that leave trailing DOM artifacts, empty formatting tags, or residual search highlight wrappers, React Editor Kit guarantees clean, pristine HTML:

  1. Spellcheck Spans Stripped: All span.mlx-spell-error tags are automatically unwrapped into pure text before onChange fires.
  2. Search Highlights Stripped: All mark.mlx-find-highlight and mark.mlx-find-current tags are unwrapped.
  3. Empty Tags Pruned: Empty <u></u>, <b></b>, <i></i>, <span></span> elements with no content are cleaned.
  4. Empty State Normalization: When all text is deleted, the editor outputs an empty string "" (or standard <p><br></p>) rather than dangling fragmented tags.

📄 License

This project is licensed under the MIT License. Free for commercial and personal applications.