State inspector — a devtool for the document model New
Rich text bugs are usually structural: a block that ended up inside an inline element, a heading level skipped, an empty inline wrapper the caret falls into and cannot leave. Those are hard to see in a rendered document and obvious in a model of it.
stateinspector.js derives that model live and checks it against 12 rules. The panel is a development aid, not a document feature: it renders nothing into your content, and nothing it draws can reach getHTML().
editor.stateInspector.open(); // the panel editor.stateInspector.issues(); // the rule violations, as data editor.stateInspector.snapshot(); // the derived model editor.stateInspector.plugins(); // what is loaded, in init order
Custom node types — declare your own content New
Inserting your own markup always worked. What was missing was declaringit, so the export paths knew what to do with it — without that, custom content survived in HTML and quietly degraded on the way to Markdown, .docx or PDF.
Register a node type once and give it only the conversions you care about. Anything you leave out falls back to the default handling, so a type that only matters in Markdown declares only toMarkdown.
editor.nodeTypes.register({
name: "callout",
match: function (el) { return el.classList.contains("my-callout"); },
toMarkdown: function (el) { return "> [!NOTE] " + el.textContent; },
toDocx: function (el) { /* ... */ }
});Hooks: toJSON, fromJSON, toMarkdown, toExportHTML, toDocx, toPdf, toWord. See Custom node types.
Ruby annotations — furigana and phonetic guides New
Proper <ruby> markup with <rp> fallbacks, so the reading degrades to base(reading) in anything that does not support ruby rather than running the two together.
<ruby>漢字<rp>(</rp><rt>かんじ</rt><rp>)</rp></ruby>
Notes
All three register in toolbar_default as well as toolbar_full. config.toolbar defaults to "default", so a plugin registered only in the full preset is invisible to every host that never configured a toolbar — with no error to say so.
The plugin bundle grows from 2,243,470 to 2,311,791 bytes (minified 954,127 to 984,902). If you load plugins individually rather than as a bundle, nothing changes until you add these three.
No core change. rte.js is the same protected build as 2.7.2, 589,759 bytes.