> Markdown version of [Rich Text Editor](https://vaadin.com/docs/latest/components/rich-text-editor). Section index: [llms.txt](https://vaadin.com/docs/latest/components/llms.txt)

# Rich Text Editor

> **Note: Commercial Feature**
>
> A commercial Vaadin subscription is required to use Rich Text Editor in your project.
>
> - [Start Free Trial](https://vaadin.com/trial)
>
> - [See Pricing](https://vaadin.com/pricing)

Rich Text Editor allows the user to author text that has rich formatting. It allows you to format and style your text using boldface, italics, headings, lists, images, links, etc.

**Lit** — `rich-text-editor-basic.ts`

```html
<vaadin-rich-text-editor
  style="max-height: 400px"
  value="${this.richText}"
></vaadin-rich-text-editor>
```

**Flow** — `RichTextEditorBasic.java`

```java
RichTextEditor rte = new RichTextEditor();
rte.setMaxHeight("400px");
String valueAsHtml = DataService.getTemplates().getRichTextHtml();
rte.setValue(valueAsHtml);
add(rte);
```

**React** — `rich-text-editor-basic.tsx`

```tsx
<RichTextEditor
  style={{ maxHeight: '400px' }}
  value={richText.value}
  onValueChanged={(event) => {
    richText.value = event.detail.value;
  }}
/>
```

## <a id="value-format"></a>Value Format

Rich Text Editor supports the HTML format and the [Quill Delta format](https://github.com/quilljs/delta) for reading and setting its value.

HTML Format Details

Rich Text Editor supports values in the HTML format, with the following restrictions:

- Only a subset of HTML tags are supported, which are listed in the table below;

- Block elements, such as paragraphs, lists, or block quotes, can’t be nested; and

- Unsupported tags, such as `<b>`, are replaced with an equivalent supported tag, such as `<strong>`, or with a paragraph (`<p>`).

Table 1. Supported HTML Tags

| Feature                                                    | Tags                             |
| ---------------------------------------------------------- | -------------------------------- |
| Paragraphs and line breaks                                 | `<p>`, `<br>`                    |
| Headings                                                   | `<h1>`, `<h2>`, …​, `<h6>`       |
| Bold, italic, underlined and strike-through text           | `<strong>`, `<em>`, `<u>`, `<s>` |
| Links                                                      | `<a href="…​">…​</a>`            |
| Text alignment via the `text-align` CSS property           | `<p style="text-align: center">` |
| Ordered, unordered lists, and list items (can’t be nested) | `<ol>`, `<ul>`, `<li>`           |
| Block quotes                                               | `<blockquote>`                   |
| Pre-formatted text                                         | `<pre>`                          |
| Images, using a Base64-encoded data URL                    | `<img src="…​">`                 |

> **Note:** Only Base64-encoded data URLs are supported for images. Web URLs are not supported.

The following snippet contains an HTML document that is supported by the component. It demonstrates the usage of several tags. Try pasting the snippet into the `HTML Value` text area in the example below and see how the editor updates. Then try modifying the value, either by using the editor’s features, or by changing the HTML value, directly.

```html
<h2>High quality rich text editor for the web</h2>
<p>Rich text editor handles the following formatting:</p>
<ul>
  <li><strong>Bold</strong></li>
  <li><em>Italic</em></li>
  <li><u>Underline</u></li>
  <li><s>Strike-through</s></li>
</ul><h3>Blockquotes</h3>
<blockquote>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et
  dolore magna aliqua.
</blockquote><h3>Code blocks</h3>
<pre spellcheck='false'>&lt;body&gt;
  &lt;vaadin-rich-text-editor&gt;&lt;/vaadin-rich-text-editor&gt;
&lt;/body&gt;
</pre>
```

Delta Format Details

The JSON-based Delta format consists of an array of operations to apply to a document. Rich Text Editor specifically only uses insert operations, each operation sequentially adding content to the document. Operations can have attributes, such as whether to render a piece of content with a specific text style, or as a link. For the full specification of the format, see the [Quill Delta GitHub repository](https://github.com/quilljs/delta).

The following snippet contains a Delta document that demonstrates some of the format’s features. Try pasting the snippet into the `Delta Value` text area in the example below and see how the editor updates. Then try modifying the value, either by using the editor’s features, or by changing the Delta value directly.

```json
[
  {"insert": "High quality rich text editor for the web\n", "attributes": {"header":  2}},
  {"insert": "Rich text editor handles the following formatting:\n"},
  {"insert": "Bold\n","attributes": { "bold": true, "list": "bullet" }},
  {"insert": "Italic\n", "attributes": { "italic": true, "list": "bullet" }},
  {"insert": "Underline\n", "attributes": { "underline": true, "list": "bullet" }},
  {"insert": "Strike-through\n", "attributes": { "strike": true, "list": "bullet" }},
  {"insert": "Blockquotes\n", "attributes": { "header": 3 }},
  {"insert": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n", "attributes": { "blockquote": true }},
  {"insert": "Code blocks\n", "attributes": { "header": 3 }},
  {"insert": "<vaadin-rich-text-editor></vaadin-rich-text-editor>\n", "attributes": { "code-block": true }}
]
```

For the Flow component, the default is the HTML format, which is also used automatically when binding the component with `Binder`.

To read, write, or bind the component’s value using the Delta format, use the [`RichTextEditor.asDelta()`](https://vaadin.com/api/platform/25.3.1/com/vaadin/flow/component/richtexteditor/RichTextEditor.html#asDelta\(\)) wrapper.

> **Note: Usage with Binder**
>
> As the component uses a complex HTML value, the default `asRequired` validator does not work as expected with `Binder`. Instead, provide a custom validator:
>
> ```java
> binder.forField(richTextEditor)
>     .asRequired(Validator.from(value -> !richTextEditor.isEmpty(), "Required"))
> ```

For the web component, to read or write the value in the Delta format, use the `value` property.

To read or write the value in the HTML format, use the `htmlValue` property and the `dangerouslySetHtmlValue` method.

> **Note: HTML Sanitization**
>
> To prevent injecting malicious content, be sure to sanitize HTML strings before passing them to the web component using `dangerouslySetHtmlValue`. An example of this would be using a library such as [dompurify](https://www.npmjs.com/package/dompurify).

**Lit** — `rich-text-editor-set-get-value.ts`

```typescript
<vaadin-rich-text-editor
  style="height: 400px;"
  .value="${this.deltaValue}"
  @value-changed="${(event: RichTextEditorValueChangedEvent) => {
    this.deltaValue = event.detail.value;
  }}"
  @html-value-changed="${(event: RichTextEditorHtmlValueChangedEvent) => {
    this.htmlValue = event.detail.value;
  }}"
></vaadin-rich-text-editor>

<vaadin-text-area
  label="HTML Value"
  helper-text="Shows the HTML representation of the edited document. You can also modify or paste HTML here to see the changes reflected in the editor above. Note that you have to leave (blur) this field in order for the editor to update."
  style="width: 100%;"
  .value="${this.htmlValue}"
  @change="${(e: TextAreaChangeEvent) => this.setHtmlValue(e.target.value)}"
></vaadin-text-area>

<vaadin-text-area
  label="Delta Value"
  helper-text="Shows the Delta representation of the edited document. You can also modify or paste the Delta JSON here to see the changes reflected in the editor above. Note that you have to leave (blur) this field in order for the editor to update."
  style="width: 100%;"
  .value="${this.deltaValue}"
  @change="${(e: TextAreaChangeEvent) => {
    this.deltaValue = e.target.value;
  }}"
></vaadin-text-area>

...

setHtmlValue(htmlValue: string) {
  this.htmlValue = htmlValue;
  this.richTextEditor.dangerouslySetHtmlValue(htmlValue);
}
```

**Flow** — `RichTextEditorSetGetValue.java`

```java
RichTextEditor rte = new RichTextEditor();
rte.getStyle().set("height", "400px");
rte.setValueChangeMode(ValueChangeMode.TIMEOUT);

// HTML value
TextArea htmlTextArea = new TextArea("HTML Value");
htmlTextArea.setHelperText(
        "Shows the HTML representation of the edited document. You can also modify or paste HTML here to see the changes reflected in the editor above. Note that you have to leave (blur) this field in order for the editor to update.");
htmlTextArea.setWidthFull();
rte.addValueChangeListener(e -> htmlTextArea.setValue(e.getValue()));
htmlTextArea.addValueChangeListener(e -> {
    if (!rte.getValue().equals(e.getValue())) {
        rte.setValue(e.getValue());
    }
});

// Delta value
TextArea deltaTextArea = new TextArea("Delta Value");
deltaTextArea.setHelperText(
        "Shows the Delta representation of the edited document. You can also modify or paste the Delta JSON here to see the changes reflected in the editor above. Note that you have to leave (blur) this field in order for the editor to update.");
deltaTextArea.setWidthFull();
rte.asDelta().addValueChangeListener(
        e -> deltaTextArea.setValue(e.getValue()));
deltaTextArea.addValueChangeListener(e -> {
    if (!rte.asDelta().getValue().equals(e.getValue())) {
        rte.asDelta().setValue(e.getValue());
    }
});

add(rte, htmlTextArea, deltaTextArea);
```

**React** — `rich-text-editor-set-get-value.tsx`

```tsx
const htmlValue = useSignal('');
const deltaValue = useSignal('');

const richTextEditorRef = useRef<RichTextEditorElement>(null);

const handleEditorChange = (event: RichTextEditorValueChangedEvent) => {
  deltaValue.value = event.detail.value;
};

const handleHtmlChange = (event: TextAreaChangeEvent) => {
  const { value } = event.target;
  htmlValue.value = value;
  if (richTextEditorRef.current) {
    richTextEditorRef.current.dangerouslySetHtmlValue(value);
  }
};

return (
  <>
    <RichTextEditor
      style={{ height: '400px' }}
      value={deltaValue.value}
      onValueChanged={handleEditorChange}
      onHtmlValueChanged={(e) => {
        htmlValue.value = e.detail.value;
      }}
      ref={richTextEditorRef}
    />

    <TextArea
      label="HTML Value"
      helperText="Shows the HTML representation of the edited document. You can also modify or paste HTML here to see the changes reflected in the editor above. Note that you have to leave (blur) this field in order for the editor to update."
      style={{ width: '100%' }}
      value={htmlValue.value}
      onChange={handleHtmlChange}
    />

    <TextArea
      label="Delta Value"
      helperText="Shows the Delta representation of the edited document. You can also modify or paste the Delta JSON here to see the changes reflected in the editor above. Note that you have to leave (blur) this field in order for the editor to update."
      style={{ width: '100%' }}
      value={deltaValue.value}
      onChange={(e) => {
        deltaValue.value = e.target.value;
      }}
    />
  </>
);
```

## <a id="read-only"></a>Read-Only

Setting the component to read-only hides the toolbar and makes the content non-editable.

**Lit** — `rich-text-editor-readonly.ts`

```html
<vaadin-rich-text-editor
  style="height: 400px;"
  readonly
  .value="${this.richText}"
></vaadin-rich-text-editor>
```

**Flow** — `RichTextEditorReadonly.java`

```java
RichTextEditor rte = new RichTextEditor();
rte.setMaxHeight("400px");
String valueAsHtml = DataService.getTemplates().getRichTextHtml();
rte.setValue(valueAsHtml);
rte.setReadOnly(true);
add(rte);
```

**React** — `rich-text-editor-readonly.tsx`

```tsx
<RichTextEditor style={{ height: '400px' }} readonly value={templates.richTextDelta} />
```

## <a id="automatic-height-adjustment"></a>Automatic Height Adjustment

Unless set to a fixed height, Rich Text Area adjusts its height automatically based on its content.

### <a id="minimum-maximum-height"></a>Minimum & Maximum Height

The automatic resizing can be restricted to a minimum and maximum height.

**Lit** — `rich-text-editor-min-max-height.ts`

```html
<vaadin-rich-text-editor
  style="min-height:200px; max-height: 400px;"
  .value="${this.richText}"
></vaadin-rich-text-editor>
```

**Flow** — `RichTextEditorMinMaxHeight.java`

```java
RichTextEditor rte = new RichTextEditor();
rte.setMaxHeight("400px");
rte.setMinHeight("200px");
String valueAsHtml = DataService.getTemplates().getRichTextHtml();
rte.setValue(valueAsHtml);
add(rte);
```

**React** — `rich-text-editor-min-max-height.tsx`

```tsx
<RichTextEditor
  style={{ minHeight: '200px', maxHeight: '400px' }}
  value={richText.value}
  onValueChanged={(event) => {
    richText.value = event.detail.value;
  }}
/>
```

## <a id="value-change-modes-flow"></a>Value Change Modes Flow

With the Flow Java API, you can define when client-side value changes are synchronized to the server. The `ValueChangeMode` enum provides the following modes:

| Mode                  | Synchronization timing                                                                                                                                           | Custom timeout interval |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- |
| `EAGER`               | Synchronizes the value whenever it changes on the client side, for example on each keystroke.                                                                    | No                      |
| `LAZY`                | Synchronizes the value after a defined interval has passed without further changes. If another change occurs before the interval ends, the timeout is restarted. | Yes                     |
| `TIMEOUT`             | Synchronizes the value at defined intervals while the value continues to change.                                                                                 | Yes                     |
| `ON_CHANGE` (default) | Synchronizes the value on the `change` event, when the component value is committed.                                                                             | No                      |

For the modes that support a custom timeout interval, you can change the interval with the `setValueChangeTimeout()` method. The default interval is 400 milliseconds.

**Flow** — `RichTextEditorValueChangeMode.java`

```java
var rte = new RichTextEditor();
rte.setMaxHeight("300px");
var modeSelector = new Select<>("Value Change Mode", valueChangeModes);
modeSelector.setValue(rte.getValueChangeMode());
modeSelector.addValueChangeListener(e -> {
    rte.setValue("");
    rte.setValueChangeMode(e.getValue());
});
var serverSideContent = new Span();
rte.addValueChangeListener(
        e -> serverSideContent.setText(e.getValue()));
```

## <a id="toolbar-actions"></a>Toolbar Actions

### <a id="history"></a>History

| Button | Title | Description                        |
| ------ | ----- | ---------------------------------- |
|        | Undo  | Reverses the previous action.      |
|        | Redo  | Restores actions undone by `Undo`. |

### <a id="emphasis"></a>Emphasis

| Button | Title         | Description           |
| ------ | ------------- | --------------------- |
| B      | Bold          | **Boldens text.**     |
| I      | Italic        | *Italicizes text.*    |
| U      | Underline     | Underlines text.      |
| T      | Strikethrough | Strikes through text. |

### <a id="color"></a>Color

| Button | Title           | Description              |
| ------ | --------------- | ------------------------ |
| A      | Text color      | Changes text color.      |
| A      | Text background | Changes text background. |

It’s possible to provide custom palette for color pickers used by the Rich Text Editor. The palette must be a list of strings in the hexadecimal color format.

**Lit**

```html
<vaadin-rich-text-editor
  .colorOptions="${['#000000', '#0066cc', '#ffffff']}"
></vaadin-rich-text-editor>
```

**Flow**

```java
RichTextEditor editor = new RichTextEditor();
editor.setColorOptions(List.of("#000000", "#0066cc", "#ffffff"));
```

**React**

```tsx
<RichTextEditor colorOptions={['#000000', '#0066cc', '#ffffff']} />
```

### <a id="headings"></a>Headings

Three different headings are available in Rich Text Editor: H1, H2, and H3. Use them to signify structure, as well as importance.

| Button | Title | Description      |
| ------ | ----- | ---------------- |
| H1     | H1    | Heading level 1. |
| H2     | H2    | Heading level 2. |
| H3     | H3    | Heading level 3. |

### <a id="subscript-superscript"></a>Subscript & Superscript

| Button | Title       | Description                                                                            |
| ------ | ----------- | -------------------------------------------------------------------------------------- |
| X      | Subscript   | Subscript text is positioned below the normal baseline and with a smaller font size.   |
| X      | Superscript | Superscript text is positioned above the normal baseline and a with smaller font size. |

### <a id="list"></a>List

| Button | Title          | Description                |
| ------ | -------------- | -------------------------- |
|        | Ordered list   | • Creates a numbered list. |
|        | Unordered list | • Creates a bulleted list. |

### <a id="alignment"></a>Alignment

| Button | Title        | Description                 |
| ------ | ------------ | --------------------------- |
|        | Left align   | Left-aligns text (default). |
|        | Center align | Center-aligns text.         |
|        | Right align  | Right-aligns text.          |

### <a id="image-link"></a>Image & Link

| Button | Title | Description                                    |
| ------ | ----- | ---------------------------------------------- |
|        | Image | Uploads and inserts an image from your device. |
|        | Link  | [Creates a hyperlink](https://vaadin.com/).    |

### <a id="blocks"></a>Blocks

| Button | Title       | Description                                   |
| ------ | ----------- | --------------------------------------------- |
| ”      | Block quote | Creates a section quoted from another source. |
| <>     | Code block  | Creates a block formatted as code.            |

### <a id="clear"></a>Clear

| Button | Title            | Description                                  |
| ------ | ---------------- | -------------------------------------------- |
|        | Clear formatting | Removes all formatting of the selected text. |

## <a id="related-components"></a>Related Components

| Component                                                             | Usage recommendations         |
| --------------------------------------------------------------------- | ----------------------------- |
| [Text Field](https://vaadin.com/docs/latest/components/text-field.md) | Basic single-line text input. |
| [Text Area](https://vaadin.com/docs/latest/components/text-area.md)   | Basic multi-line text input.  |

`DC8286C2-D152-4234-831F-F90A00B97305`
