<bmx-rich-text-editor>
A rich text editor that keeps everything in the page: no cloud service, no licence server, no script loaded from anywhere. Headings, marks, colour, links, bulleted, numbered and check lists, quotes, code blocks, tables, images, dividers; a slash menu for blocks, mentions of people, Markdown typed as you go, find and replace, comments with replies, tracked changes to accept or reject, the HTML source, and full screen. Paste from Word or Google Docs arrives clean, and everything that reaches the document - typed, pasted, dropped, loaded - passes the same sanitiser, so it cannot carry script.
23 properties · 6 events · 21 methods · 9 parts
Example
Release notes
This release brings charts, a rich text editor and a new site. Select any text and press the comment button, or switch on Track changes and edit.
- Write the release notes
- Check them with the team
What changed
| Area | Change |
|---|---|
| Charts | Twenty-two kinds of chart |
| Editors | Comments and tracked changes |
Everything stays in the page: nothing is sent anywhere.
<bmx-rich-text-editor name="body"></bmx-rich-text-editor>
The editor's value appears here.
Show markup
<bmx-rich-text-editor
id="ex-rte"
lang="en-GB"
label="Release notes"
placeholder="Write here. Type / for blocks, @ to mention someone."
author="Sundar"
style="--bmx-rich-text-editor-min-height: 16rem; --bmx-rich-text-editor-max-height: 28rem"
>
<h2>Release notes</h2>
<p>This release brings <strong>charts</strong>, a <em>rich text editor</em> and a <a href="https://binarymission.co.uk">new site</a>. Select any text and press the comment button, or switch on <strong>Track changes</strong> and edit.</p>
<ul data-type="checklist">
<li data-checked="true">Write the release notes</li>
<li data-checked="false">Check them with the team</li>
</ul>
<h3>What changed</h3>
<table>
<thead><tr><th>Area</th><th>Change</th></tr></thead>
<tbody>
<tr><td>Charts</td><td>Twenty-two kinds of chart</td></tr>
<tr><td>Editors</td><td>Comments and tracked changes</td></tr>
</tbody>
</table>
<blockquote>Everything stays in the page: nothing is sent anywhere.</blockquote>
<pre data-language="html"><code><bmx-rich-text-editor name="body"></bmx-rich-text-editor></code></pre>
</bmx-rich-text-editor>
<div class="row" style="margin-block-start: 1rem; gap: 0.5rem; flex-wrap: wrap">
<button type="button" id="ex-rte-html">Show the HTML</button>
<button type="button" id="ex-rte-md">Show the Markdown</button>
<button type="button" id="ex-rte-json">Show the JSON</button>
</div>
<pre id="ex-rte-out" class="note" style="margin-block-start: 0.75rem; max-block-size: 16rem; overflow: auto; white-space: pre-wrap">The editor's value appears here.</pre>
<script type="module">
await customElements.whenDefined('bmx-rich-text-editor');
const editor = document.getElementById('ex-rte');
const out = document.getElementById('ex-rte-out');
editor.mentions = [
{ id: 'u1', label: 'Ann Lee', description: 'Design' },
{ id: 'u2', label: 'Bo Chen', description: 'Sales' },
{ id: 'u3', label: 'Cara Diaz', description: 'Support' },
];
editor.comments = [];
document.getElementById('ex-rte-html').addEventListener('click', async () => (out.textContent = await editor.toHTML()));
document.getElementById('ex-rte-md').addEventListener('click', async () => (out.textContent = await editor.toMarkdown()));
document.getElementById('ex-rte-json').addEventListener('click', async () => (out.textContent = JSON.stringify(await editor.toDocumentJSON(), null, 2)));
editor.addEventListener('bmxRteCommentsChange', event => (out.textContent = `Comments: ${JSON.stringify(event.detail.comments, null, 2)}`));
</script>
The value is HTML, posted with its form under name; toMarkdown(),
toText() and toDocumentJSON() give it in other shapes, and
loadMarkdown() loads Markdown. Images are kept in the document as data unless an
imageHandler stores them where the application wants.
The text being edited sits in the element's light DOM, so that the browser's own selection, spelling and input methods behave the same in every engine; its styles are scoped to the editor.
Properties
| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
author |
author |
string |
'You' |
The name tracked changes and comments are written under. |
comments |
comments |
readonly BmxRteComment[] | string |
[] |
The comments on the document. JSON in markup. Updated as comments are added, answered and resolved. |
disabled |
disabled |
boolean |
false |
Neither editable nor posted with its form. |
fullscreen |
fullscreen |
boolean |
false |
Show the editor over the whole window. |
hideChanges |
hide-changes |
boolean |
false |
Show tracked deletions struck through (default) or hide them, showing the text as it would read. |
imageHandler |
property only | (file: File) => Promise<string> |
— | Stores an image the reader adds and returns its URL. Default: the image is kept in the document as data. |
images |
images |
boolean |
true |
Allow images. |
label |
label |
string |
— | What the editor is for, said by screen readers. |
markdownShortcuts |
markdown-shortcuts |
boolean |
true |
Turn # , - , 1. , > , [] , ``` and **bold** into formatting as they are typed. |
maxLength |
max-length |
number |
— | At most this many characters of text. |
mentionSource |
property only | (query: string) => readonly BmxRteMentionItem[] | Promise<readonly BmxRteMentionItem[]> |
— | Finds people to |
mentions |
mentions |
readonly BmxRteMentionItem[] | string |
— | People (or anything) to |
name |
name |
string |
— | The name the value is posted under with its form. |
placeholder |
placeholder |
string |
— | Shown while the document is empty. |
readonly |
readonly |
boolean |
false |
Shown but not editable. |
required |
required |
boolean |
false |
The form will not submit while the document is empty. |
spellcheck |
spellcheck |
boolean |
true |
Underline misspellings, as the browser does. |
statusBar |
status-bar |
boolean |
true |
Show the word count and the review buttons under the document. |
strings |
strings |
Partial<BmxRteStrings> | string |
— | Words the editor shows or says: any of BmxRteStrings. JSON in markup. |
toolbar |
toolbar |
string | readonly string[] |
'full' |
The toolbar: full (default), basic, minimal, or a list of items (bold,italic,|,link). |
toolbarMode |
toolbar-mode |
'top' | 'bubble' | 'both' | 'none' |
'top' |
Where the toolbar is: top (default), bubble (over a selection), both or none. |
tracking |
tracking |
boolean |
false |
Record typing and deleting as changes to accept or reject. |
value |
value |
string |
'' |
The document as HTML. Set it to load one; read it (or listen for bmxRteInput) for what was written. |
Events
| Event | Detail | Description |
|---|---|---|
bmxRteChange |
BmxRteValueDetail |
The document changed and the editor lost focus, as a field's change does. |
bmxRteCommentsChange |
BmxRteCommentsDetail |
A comment was added, answered, resolved, reopened or deleted. comments is the whole new list. |
bmxRteInput |
BmxRteValueDetail |
The document changed (typing, a command, a paste). |
bmxRteMention |
BmxRteMentionDetail |
Someone was |
bmxRteSelectionChange |
BmxRteFormats |
The formats at the caret changed. |
bmxRteTrackedChange |
BmxRteChangesDetail |
The tracked changes changed. |
Methods
| Method | Signature | Description |
|---|---|---|
acceptChange |
acceptChange(id?: string) => Promise<number> |
Accepts one tracked change by id, or all of them. |
addCommentToSelection |
addCommentToSelection(text: string) => Promise<string | null> |
Adds a comment to the selected text. Returns its id, or null with nothing selected. |
clear |
clear() => Promise<void> |
Empties the document. |
execCommand |
execCommand(name: string, value?: string) => Promise<void> |
Runs a command, as its toolbar button does: bold, italic, underline, strike, code, p, h1-h6, quote, codeBlock, bulletList, orderedList, checklist, alignLeft, alignCenter, alignRight, alignJustify, indent, outdent, textColor and highlight (with a colour), unlink, rule, clear, undo, redo, find, track, source, fullscreen and the table commands. |
getChanges |
getChanges() => Promise<readonly BmxRteChange[]> |
Every tracked change. |
getStats |
getStats() => Promise<{ words: number; characters: number; }> |
Words and characters. |
insertHTML |
insertHTML(html: string) => Promise<void> |
Inserts HTML (sanitised) at the caret, or at the end when the editor has none. |
insertTableAt |
insertTableAt(cols?: number, rows?: number) => Promise<void> |
Inserts a table of cols by rows (the first row a header). |
insertText |
insertText(text: string) => Promise<void> |
Inserts text at the caret. |
loadHTML |
loadHTML(html: string, keepHistory?: boolean) => Promise<void> |
Loads HTML (sanitised). With keepHistory, the change can be undone. |
loadMarkdown |
loadMarkdown(markdown: string, keepHistory?: boolean) => Promise<void> |
Loads Markdown. |
redo |
redo() => Promise<void> |
Redoes what was undone. |
rejectChange |
rejectChange(id?: string) => Promise<number> |
Rejects one tracked change by id, or all of them. |
replaceAll |
replaceAll(query: string, replacement: string, matchCase?: boolean) => Promise<number> |
Replaces every match of query with replacement. Returns how many. |
setFocus |
setFocus() => Promise<void> |
Moves focus into the document. |
setLink |
setLink(href: string, newTab?: boolean) => Promise<void> |
Adds a link to the selection, or changes the one at the caret. |
toDocumentJSON |
toDocumentJSON() => Promise<BmxRteJsonNode> |
The document as a tree of blocks, marks and text. |
toHTML |
toHTML() => Promise<string> |
The document as sanitised HTML (the same as value). |
toMarkdown |
toMarkdown() => Promise<string> |
The document as Markdown (GitHub's dialect). |
toText |
toText() => Promise<string> |
The text, as a reader sees it, with tracked deletions left out. |
undo |
undo() => Promise<void> |
Undoes the last change. |
Slots
| Slot | Description |
|---|---|
surface |
(managed by the editor) the editing surface. |
CSS shadow parts
| Part | Description |
|---|---|
bubble |
the toolbar over a selection. |
button |
a toolbar button. |
comments |
the comments panel. |
find |
the find and replace bar. |
frame |
the editor's border and background. |
popover |
a menu or form opened from the toolbar. |
source |
the HTML source view. |
status |
the status bar. |
toolbar |
the toolbar. |
CSS custom properties
| Property | Description |
|---|---|
--bmx-rich-text-editor-background |
Behind the document. |
--bmx-rich-text-editor-font |
The document's typeface. Default the library's. |
--bmx-rich-text-editor-font-size |
The document's text size. Default 1rem. |
--bmx-rich-text-editor-max-height |
The document's greatest height before it scrolls. Default none. |
--bmx-rich-text-editor-min-height |
The document's least height. Default 10rem. |
--bmx-rich-text-editor-toolbar-background |
Behind the toolbar. |