---
name: rich-text-editor
category: inputs
summary: "Contenteditable region with a formatting toolbar"
subpath: "@42/core/rich-text-editor"
---

Toolbar of `execCommand` formatting actions wired to a `contenteditable` region.

```html
<div data-c42-rich-text-editor>
  <div data-c42-rte-toolbar>
    <button data-c42-rte-command="bold" aria-label="Bold"><b>B</b></button>
    <button data-c42-rte-command="italic" aria-label="Italic"><i>I</i></button>
    <button data-c42-rte-command="insertUnorderedList" aria-label="List">• List</button>
    <button data-c42-rte-command="createLink" aria-label="Link">Link</button>
  </div>
  <div data-c42-rte-content data-placeholder="Write something…"></div>
</div>
```

```ts
import { RichTextEditor } from '@42/core/rich-text-editor';
const editor = new RichTextEditor(root, { value: '<p>Hi</p>' });
editor.format('bold');
editor.on('richtexteditor:change', (e) => console.log(e.detail.html));
```

Toolbar buttons carry `data-c42-rte-command` (any `document.execCommand` name);
pass a static argument with `data-value` (e.g. `formatBlock` → `data-value="h2"`).
`createLink` resolves its URL from the `getLinkUrl` option (defaults to
`window.prompt`). Toggle commands reflect their state on the button via
`aria-pressed` + `data-active`. An empty editor gets `data-empty` so the theme
can show `data-placeholder`.

> `document.execCommand` is deprecated but still the most broadly supported
> inline-formatting API (with native undo). It is feature-detected and guarded.

Options: `value` (initial HTML), `getLinkUrl` (() => string | null)
Methods: `format(command, value?)`, `getHTML()`, `setHTML(html)`, `focus()`
Events: `richtexteditor:command` → `{ command, value? }`, `richtexteditor:change` → `{ html }`
