> ## Documentation Index
> Fetch the complete documentation index at: https://anvil.servicetitan.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Rich Text Editor - Web

> RichTextEditor is a rich text editing field with a configurable toolbar supporting text formatting, lists, links, mentions, and media.

> [!NOTE]
>
> For development, import `RichTextEditor` from
> `@servicetitan/anvil2/beta`. For design, find it in the
> [Anvil2 file](https://www.figma.com/design/xaNQsvRKczoxu7pj0M6QT8/Anvil2-v3?node-id=2861-1506).

> [!NOTE]
>
> **Beta Feature**
>
> This feature is currently in beta, and needs to be imported from `@servicetitan/anvil2/beta`.
>
> While we hope to minimize breaking changes, they may occur due to feedback we receive or other improvements. These will always be documented in the changelog and communicated in Slack.
>
> Please reach out in the [#ask-designsystem](https://servicetitan.enterprise.slack.com/archives/CBSRGHTRS) channel with any questions or feedback!

**Implementation**

## Live Component Playground

rich-text-editor-playground

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/rich-text-editor-playground?file=src/App.tsx)

## Common Examples

### Basic Usage

A minimal editor with the default toolbar — text formatting and alignment enabled, everything else off.

rich-text-editor-basic

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/rich-text-editor-basic?file=src/App.tsx)

### Error and Validation

Pass an error message string to `error` to display validation feedback below the editor.

rich-text-editor-error

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/rich-text-editor-error?file=src/App.tsx)

### Read-only

Pass `disabled` to prevent editing. The toolbar remains visible but all controls are disabled.

rich-text-editor-readonly

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/rich-text-editor-readonly?file=src/App.tsx)

### With Mentions

Enable `allowMention` and supply `mentionOptions` to support @mention typeahead. Use `onMentionInputChange` to filter options as the user types, and `renderMentionHoverContent` to show a custom hover card over inserted mentions.

rich-text-editor-with-mentions

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/rich-text-editor-with-mentions?file=src/App.tsx)

### With Media

Enable `allowMedia` with a required `onImageUpload` handler to support image uploads and YouTube embeds.

rich-text-editor-with-media

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/rich-text-editor-with-media?file=src/App.tsx)

### All Features

All toolbar sections enabled together: formatting, alignment, lists, checklist, code, blockquote, link, mentions, drag-and-drop, and media.

rich-text-editor-with-all-features

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/rich-text-editor-with-all-features?file=src/App.tsx)

## Controlled vs Uncontrolled

`RichTextEditor` supports both controlled and uncontrolled modes.

* **Uncontrolled** — Pass `defaultValue` to set initial HTML content. The editor manages its own internal state.
* **Controlled** — Pass `value` and `onChange` to manage content externally. `onChange` fires on every change with the serialized HTML string.

Use `onJsonChange` when you need access to TipTap's JSON representation for more granular content handling.

## Toolbar Features

Each toolbar section is opt-in via a corresponding `allow*` prop. Text formatting and alignment are enabled by default; all other sections are disabled unless explicitly enabled.

| Feature | Prop | Default |
| - | - | - |
| Text type, font size, bold, italic, underline, strikethrough | `allowTextFormat` | `true` |
| Left, center, right, justify alignment | `allowTextAlignment` | `true` |
| Ordered and unordered lists, indent controls | `allowLists` | `false` |
| Checklist (task list) | `allowChecklist` | `false` |
| Inline code | `allowCode` | `false` |
| Blockquote | `allowBlockquote` | `false` |
| Link insert and remove | `allowLink` | `false` |
| @mention typeahead | `allowMention` | `false` |
| Drag handle for block reordering | `allowDragDrop` | `false` |
| Image upload and YouTube embedding | `allowMedia` | `false` |

## Mentions

Enable @mention support with `allowMention`. Supply `mentionOptions` as an array of `{ id, label }` objects and use `onMentionInputChange` to filter options dynamically as the user types.

Customize the dropdown item appearance with `renderMentionOption` and the hover card shown over inserted mentions with `renderMentionHoverContent`.

## Media

Enable image and YouTube embedding with `allowMedia`. When `allowMedia` is `true`, `onImageUpload` is required. The callback receives the selected `File[]` and an `onComplete` callback — invoke it with the resolved image URLs once upload finishes.

```tsx theme={null}
<RichTextEditor
  allowMedia
  onImageUpload={(files, onComplete) => {
    uploadFiles(files).then((urls) => onComplete(urls));
  }}
/>
```

Control accepted file types with `allowedMimeTypes`. When omitted, the editor defaults to common image formats.

**RichTextEditor Props**

```tsx theme={null}
import { RichTextEditor } from "@servicetitan/anvil2/beta";

<RichTextEditor label="Notes" />
```

## `RichTextEditor` Props

The `RichTextEditor` accepts the following props. It also extends `LayoutUtilProps` for spacing and sizing utilities.

**allowBlockquote** `boolean` (default: false)

Enables the blockquote toolbar button.

**allowChecklist** `boolean` (default: false)

Enables the checklist (task list) toolbar button.

**allowCode** `boolean` (default: false)

Enables the inline code toolbar button.

**allowDragDrop** `boolean` (default: false)

Enables a drag handle for reordering content blocks.

**allowedMimeTypes** \`\`image/\$\{string}`[]`

MIME types accepted by the file picker and paste/drop handler when `allowMedia` is `true`. Defaults to common image formats when omitted.

**allowLink** `boolean` (default: false)

Enables the link insert and remove toolbar button.

**allowMedia** `boolean` (default: false)

Enables the Insert dropdown with Image and YouTube options. When `true`, `onImageUpload` is required.

**allowMention** `boolean` (default: false)

Enables the @mention toolbar button and typeahead dropdown. Requires `mentionOptions` to populate the dropdown.

**allowTextAlignment** `boolean` (default: true)

Enables the text alignment toolbar section: left, center, right, and justify.

**allowTextFormat** `boolean` (default: true)

Enables the text formatting toolbar section: text type dropdown, font size, bold, italic, underline, and strikethrough.

**defaultValue** `string`

Initial content for uncontrolled mode. Accepts an HTML string (e.g., `"<p>Hello <strong>world</strong></p>"`) or a plain string, which the editor wraps in a `<p>` tag.

**description** `ReactNode`

Description text displayed below the editor.

**disabled** `boolean` (default: false)

Disables the editor and all toolbar controls.

**error** `boolean | string | string[]`

Error state. Pass `true` for error styling only, or a string or string array to display error messages below the editor.

**hint** `ReactNode`

Hint text displayed below the editor.

**id** `string`

HTML id applied to the editor's contenteditable element.

**label** `ReactNode`

Label for the editor field.

**labelProps** `FieldLabelProps`

Additional props passed to the label element.

**mentionOptions** `RichTextEditorMentionOption[]`

Options displayed in the @mention typeahead dropdown. Each option requires an `id` and `label`.

**moreInfo** `ReactNode`

Additional info content rendered alongside the label, typically used for tooltips or help text.

**onChange** `(html: string) =\> void`

Callback fired with the serialized HTML string on each content change.

**onImageUpload** `(files: File[], onComplete: (srcs: string[]) =\> void) =\> void`

Required when `allowMedia` is `true`. Called when the user selects, pastes, or drops image files. Invoke `onComplete` with the resolved image URLs once upload finishes.

**onJsonChange** `(json: JSONContent) =\> void`

Callback fired with the TipTap JSON representation on each content change.

**onMentionInputChange** `(query: string) =\> void`

Fired when the user types after `@`. Use this to filter or async-load `mentionOptions`.

**placeholder** `string`

Placeholder text shown when the editor is empty.

**renderMentionHoverContent** `(option: RichTextEditorMentionOption) =\> ReactNode`

Custom render function for the hover card shown when hovering over an inserted @mention.

**renderMentionOption** `(option: RichTextEditorMentionOption) =\> ReactNode`

Custom render function for each option row in the @mention typeahead dropdown.

**required** `boolean`

Marks the field as required and adds a visual indicator to the label.

**value** `string`

Controlled HTML content. Use with `onChange` to update the value on each change.

## `RichTextEditorMentionOption` Type

A single option displayed in the @mention typeahead dropdown.

```tsx theme={null}
type RichTextEditorMentionOption = {
  id: string;
  label: string;
};
```

**id** `string` *required*

Unique identifier for the mention option, stored as an attribute on the inserted mention node.

**label** `string` *required*

Display name shown in the @mention dropdown and rendered inside the inserted mention node.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.