Release notes · May 19, 2026

RichTextEditor npm 2.2.3

Editing-experience push — 88 small-to-medium UX features added in one wave. No breaking changes; everything opt-out via config.

npm 2.2.3

Smart typography while you type New

The editor now recognises five common typing patterns and substitutes the Unicode typographic glyph automatically — skipped inside <code>, <pre>, and <kbd> blocks so code samples stay verbatim.

  • Auto-link on space — URLs, www. hosts, and email addresses wrap into <a> the moment you press space. javascript:, vbscript:, and non-image data: URIs are blocked.
  • Em-dash-- becomes —.
  • Ellipsis... becomes ….
  • Smart quotes — straight "x" becomes “x”; it's becomes it’s (letter-aware apostrophe).
  • Trademarks(c), (r), (tm) become ©, ®, ™.

Opt-out master switch: config.smartTypography = false. Per-feature flags also available.

23 keyboard shortcuts at Google Docs / Word parity New

Every shortcut shows in toolbar tooltips (Mac auto-detects & uses ⌘ ⇧ ⌥). Press Ctrl+/ anywhere in the editor for the full cheat-sheet modal.

  • Headings: Ctrl+Alt+1..6, normal paragraph Ctrl+Alt+0
  • Lists: numbered Ctrl+Shift+7, bullet Ctrl+Shift+8, blockquote Ctrl+Shift+9
  • Align: Ctrl+Shift+L / E / R / J
  • Strike / Sub / Super / Clear: Ctrl+Shift+X, Ctrl+,, Ctrl+., Ctrl+\
  • Insert: link Ctrl+K, horizontal rule Ctrl+Shift+-
  • Paste plain: Ctrl+Shift+V
  • Highlight (yellow <mark>): Ctrl+Shift+H
  • Duplicate block: Ctrl+Shift+DMove block up / down: Alt+↑ / ↓
  • Cycle case (UPPER → lower → Title): Ctrl+Shift+K
  • Sort lines (alphabetical): Ctrl+Shift+Alt+S
  • Reading mode (distraction-free): Ctrl+Shift+M — persists across reloads via localStorage
  • Word count details: Ctrl+Shift+C
  • Cheat sheet: Ctrl+/

Auto-generated heading anchor IDs + copy-link on hover New

Every h1h6 automatically receives a stable slug ID derived from its text (NFKD-normalised, lower-case, hyphenated, deduped). Hover a heading and a small 🔗 chip appears; click it to copy the deep-link (current URL plus the slug) to your clipboard. TOC plugins, share-link patterns, and screen-reader navigation all work without manual ID assignment.

Smart paste from Word + Google Docs Improved

Two paste-cleanup paths landed:

  • Word internal-bookmark anchors (<a name="OLE_LINK1">, <a name="_Toc..."> etc.) are stripped on paste so the text doesn’t arrive as blue-underlined links. Anchors with a real href survive unchanged.
  • Google Docs wrapper (<b id="docs-internal-guid-..."> that makes everything bold) gets unwrapped, leaving only the genuine formatting.

When either path fires, a brief toast appears bottom-centre: “Cleaned from Word — Undo: Ctrl+Z”. Opt-out via config.smartPasteToast = false.

Restricted editing templates New

Word-style “protect document with editable regions.” Pass restrictedEditingMode: true to lock the document; mark fillable spans at runtime with editor.restrictedEditing.markSelection(). Use it for contracts, forms, and fillable templates — only the marked regions accept input. Tab between regions via goToNext() / goToPrev(); regions get a soft green outline for discoverability. Full TypeScript declarations shipped in index.d.ts.

Markdown round-trip New

Two new instance methods: editor.toMarkdown() (HTML → CommonMark subset) and editor.fromMarkdown(md, { apply }) (CommonMark → HTML). Round-trips through headings, bold / italic / strike / code, links, images, lists with proper indented nesting, blockquotes, horizontal rules, fenced code blocks, and pipe-tables. Round-trip-stable with the existing markdown-shortcut parser.

Smart-find live highlight + match count New

editor.openFindDialog() shows a small floating panel with a live count badge (“3 of 12”), Prev / Next navigation that auto-scrolls to the active hit, Replace single + Replace all. Every match is wrapped in <mark class="rte-find-hit"> so you can see the matches at a glance. Programmatic: editor.findHighlight(query, { caseSensitive }) returns { matches }.

Auto-save with status New

Pass config.autoSave = { onSave: function(html) {...} } and the editor debounces saves, hashes content to skip no-op writes, and renders “Saving…” → “✓ Saved at HH:MM” in the status bar. Promise-aware (waits for your save to resolve before flipping to ✓); failure-aware (shows ⚠ on rejected promise / thrown error). Programmatic: editor.autoSave.trigger(), isDirty(), lastSavedAt().

Auto-grow, sticky toolbar, reading mode, block drag handles New

Four composable mode switches for layout flexibility.

  • config.autoGrow = true — editor expands to fit content, no inner scrollbar.
  • config.stickyToolbar = true — toolbar sticks to top of viewport on long pages.
  • editor.toggleReadingMode() + Ctrl+Shift+M — distraction-free, hides chrome.
  • config.blockDragHandles = true — Notion-style ⁞ handle appears on hover; drag to reorder paragraphs/lists/tables.

Editing-flow fixes that just match expectations UX

  • Enter on an empty <li> exits the list (no more chains of empty bullets).
  • Enter on an empty blockquote line exits the blockquote.
  • Backspace at column 0 of an <li> outdents one level instead of merging into the previous paragraph.
  • Backspace at column 0 of a blockquote exits the blockquote.
  • Tab in a list nests; Shift+Tab outdents.
  • Image upload inserts inline at the caret — no more forced centring.
  • Insert table defaults to width:100%; cells get visible borders (dotted in toggle-border mode) and minimum dimensions so empty tables don’t vanish.
  • Snippets: type :date / :time / :datetime / :hr + Tab; register your own with editor.snippets.register(":sig", "<p>...</p>", { isHtml: true }).

Selection chrome polish UX

  • Inline link URL preview — clickable URL appears in the float toolbar when caret is in an <a>; opens in a new tab safely with rel="noopener noreferrer".
  • Image hover quick-action bar — floating Alt / Replace / × chips appear when hovering an <img>; Replace opens a file picker, × deletes the image.
  • Inline alt-text editor — images missing alt get a dashed amber outline; click to open an inline popup that sets the alt attribute.
  • Video (IFRAME) float toolbar — gets the same handles + action chips as images.
  • Table column & row resize handles — hover near a border, cursor changes to resize, drag to resize.
  • Float toolbar icons enlarged 22 → 30 px button / 14 → 18 px SVG, all toolbars.

Print preview + PDF export New

editor.printPreview() opens a clean print-ready window; editor.exportPdf({ title }) additionally auto-triggers the print dialog so the user can pick “Save as PDF” as the destination — browser-native, no library required. A @media print stylesheet hides all toolbar / chrome / handles so only the document content prints.

Math markup hook New

editor.applyMathMarkup() wraps every $x^2$ run in <span class="rte-math-inline" data-tex="x^2">; editor.renderMath() additionally detects KaTeX or MathJax v3+ on the host page and dispatches to it. No bundling — you bring your own renderer, the editor provides stable markup.

Right-click “Ask AI” context menu AI

When a text selection is non-empty and the AI Toolkit plugin is wired, right-click shows a compact menu: ✨ Ask AI to explain, ✏️ Rewrite, 📝 Summarize, 🌐 Translate. Each entry calls editor.aiToolkit.openDialog({ mode }). Disable with config.aiContextMenu = false.

DOCX import endpoint Server

New: POST /richtextbox/import/docx on the ASP.NET Core RichTextBox.AspNetCore package. Accepts multipart/form-data with a .docx file; returns { html, mode, fileName }. Client wrapper: editor.aiToolkit.importDocx({ url, file, mode }) — opens a file picker if file is omitted, then applies via insertHTML or setHTMLCode. Uses DocumentFormat.OpenXml; conservative HTML subset (p, strong, em, u, h1–h6, ul / ol / li, br, table / tr / td) that round-trips with the existing DOCX export.

Robustness fixes Bug fix

Five real-world regressions resolved this wave:

  • Chrome iframe document-swap recovery. Chrome fires a deferred about:blank load AFTER our synchronous contentDocument.open/write/close, replacing the document. Closure refs (editdoc / editable / editsel) now reseat to the live document; all 18 iframe listeners re-bind. Fixes “editor renders but typing does nothing” on multi-editor pages.
  • Toolbar null-guard. A single unknown button command in the toolbar config no longer crashes the toolbar build half-way through, leaving the editor visually-rendered-but-non-editable.
  • Image insertion at caret. Persistent __lastInEditorRange tracker ensures the file-picker flow inserts the upload at the original caret position even if focus shifted in between (reported by Nathan Allen / Kenneth Chen).
  • Plugin-button crash on empty selection. _editsel_getRange() synthesises a collapsed range at end-of-content when callers (emoji panel, gallery, image dialog) fire from outside the iframe and the editor has never been focused.
  • NuGet DocumentFormat.OpenXml now declared as a PackageReference in the generated demo csproj so trial download bundles include the dependency (reported by Kenneth Chen).

Install or upgrade

Grab the latest via npm:

npm install @richscripts/richtexteditor@latest

Feedback & issues: support@richtexteditor.com