Release notes · September 3, 2026

RichTextEditor 2.6.4

Core 2.5.7: an undo bug that looked like data loss, IME composition handling, a paste parser fix, and the sanitizer keeping comments.

2.6.4

One Ctrl+Z after loading a document blanked it Fix

setHTMLCode() did not seed the undo baseline, so the baseline stayed the empty document and the last available undo discarded your content instead of returning to it. Every framework wrapper was affected, because React, Vue, Angular and Svelte all load through setEditorValue()setHTMLCode(). Load a document, type one character, press Ctrl+Z, and the document went blank. Redo recovered it, but on the most common keystroke in an editor it looked exactly like data loss.

IME composition fired a change event per keystroke Fix

There was no compositionstart/compositionend handling anywhere — not in the core, not in any wrapper. Composing 你好 produced 4 change events instead of 1, and intermediate phonetic buffers could become undo steps. A controlled component that writes the value back mid-composition tears down the IME buffer. Now 0 events while composing and 1 on commit.

Wrappers serialised the whole document on every keystroke Performance

React, Vue, Angular and Svelte each called a full getHTMLCode() inside the change handler with no coalescing — and again in controlled mode for the value comparison. On a 3,000-paragraph (134 KB) document, typing 19 characters cost 19 serialisations and 1,735 ms; it now costs 1 and 90 ms. New optional changeDelay prop (default 120 ms; 0 restores the old synchronous behaviour).

Unquoted attributes had their first character duplicated Fix

The paste and import parser passed the value’s first character as the quote and the rest as the value: class=hello became class="helloh", and single-character values vanished entirely — cellpadding=0 was dropped. Unquoted attributes are legal HTML and are what Word emits, which is why Word’s class=MsoNormal survived the Mso filter as MsoNormalM and leaked into saved content.

HTML comments are preserved again Fix

The sanitizer deleted every comment on the theory that “comments can hide markup”. That is not true — serialise a commented-out script, re-parse it, and it is inert. Only the small enumerable set of comment data that cannot survive serialisation is dropped now. This restores CMS marker round-tripping and Outlook conditional comments, which emailtoolkit.js depends on.

Sanitizer allowlists accept patterns New

sanitizerAllowTags and sanitizerAllowAttributes now take "x-*" wildcards and regular expressions, not just exact names — the difference between a usable general-HTML-support equivalent and one that makes you enumerate every element a CMS might emit. Wildcards are matched by hand rather than compiled, so a config value can never become a regex-injection vector.

Split-button arrows now meet WCAG 2.5.8 Accessibility

The dropdown half of a split button was 14×24 CSS px, failing Target Size (Minimum), Level AA, which requires 24×24 — and the spacing exception cannot apply, because the halves are adjacent by construction. Widening the arrow alone made it worse (the fixed-width row shrank both halves to 19 px), so the container widened too. Split buttons are 48 px instead of 38 px. The 44 px AAA target is unchanged and still not claimed.

16 slash commands were unreachable Fix

Plugins sorting before slashcommand.js registered their entries before the registry existed and were silently dropped, and the plugin evaluated its feature gates once at init — before later-sorting plugins defined their APIs. Defaults now refresh after all plugins initialise and when the menu opens. The menu went from 68 to 82 entries, and every entry is now localizable.

Install or upgrade

Grab the latest via npm:

npm install @richscripts/richtexteditor@latest

Feedback & issues: support@richtexteditor.com