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

# Official Features

> Reference for the features included with FrogBot's Lexical editor.

Features add editing controls, node types, and conversion behavior. Import them from `@frogbotai/richtext-lexical` and pass them to `lexicalEditor`.

Every feature is configurable. You can use the recommended defaults, remove features you do not need, or add your own feature providers.

## Features overview

| Feature | Default | Description |
| - | - | - |
| `BoldFeature` | Yes | Bold text formatting. |
| `ItalicFeature` | Yes | Italic text formatting. |
| `UnderlineFeature` | Yes | Underlined text formatting. |
| `StrikethroughFeature` | Yes | Strikethrough text formatting. |
| `SubscriptFeature` | Yes | Subscript formatting. |
| `SuperscriptFeature` | Yes | Superscript formatting. |
| `InlineCodeFeature` | Yes | Inline code formatting. |
| `ParagraphFeature` | Yes | Paragraph creation and conversion controls. |
| `HeadingFeature` | Yes | Configurable H1-H6 heading nodes. |
| `AlignFeature` | Yes | Left, center, right, and justified alignment. |
| `IndentFeature` | Yes | Block indentation and tab behavior. |
| `UnorderedListFeature` | Yes | Bulleted lists. |
| `OrderedListFeature` | Yes | Numbered lists. |
| `ChecklistFeature` | Yes | Interactive checklists. |
| `LinkFeature` | Yes | External and internal links. |
| `RelationshipFeature` | Yes | Block-level record relationships. |
| `BlockquoteFeature` | Yes | Block quotes. |
| `UploadFeature` | Yes | File nodes for upload-enabled collections. |
| `HorizontalRuleFeature` | Yes | Horizontal separators. |
| `InlineToolbarFeature` | Yes | Floating toolbar for selected text. |
| `FixedToolbarFeature` | No | Persistent toolbar above the editor. |
| `BlocksFeature` | No | Block and inline-block nodes with custom fields. |
| `TreeViewFeature` | No | Editor-state and DOM debugging panel. |
| `TableFeature` | No | Table editing. |
| `TextStateFeature` | No | Key-value text attributes mapped to inline styles. |

Each feature is a function that returns a feature provider, such as `BoldFeature()`. The features with options are documented below. Every other feature takes no arguments: `BoldFeature`, `ItalicFeature`, `UnderlineFeature`, `StrikethroughFeature`, `SubscriptFeature`, `SuperscriptFeature`, `InlineCodeFeature`, `ParagraphFeature`, `AlignFeature`, `UnorderedListFeature`, `OrderedListFeature`, `ChecklistFeature`, `BlockquoteFeature`, `HorizontalRuleFeature`, `InlineToolbarFeature`, `TreeViewFeature`, and `TableFeature`.

## Configure headings

Bold, italic, underline, strikethrough, subscript, superscript, and inline code features add their corresponding formatting controls. Bold, italic, underline, and inline code also support their conventional keyboard shortcuts. Paragraph, heading, list, quote, and horizontal-rule features add slash-menu and toolbar entries, as applicable.

```ts theme={"theme":"tokyo-night"}
import { HeadingFeature, lexicalEditor } from '@frogbotai/richtext-lexical'

const editor = lexicalEditor({
  features: ({ defaultFeatures }) => [
    ...defaultFeatures,
    HeadingFeature({
      enabledHeadingSizes: ['h2', 'h3', 'h4'],
    }),
  ],
})
```

| Option | Type | Default | Description |
| - | - | - | - |
| `enabledHeadingSizes` | `('h1' \| 'h2' \| 'h3' \| 'h4' \| 'h5' \| 'h6')[]` | All six sizes | Heading levels editors can create from the toolbar, slash menu, and Markdown shortcuts. The editor changes a heading at any other level, such as a pasted one, to the smallest enabled level, and validation rejects saved headings at other levels. |

## Configure indentation

Use `disableTabNode` to reserve Tab for block-level indentation. `disabledNodes` prevents selected node types from being indented.

```ts theme={"theme":"tokyo-night"}
import { IndentFeature } from '@frogbotai/richtext-lexical'

IndentFeature({
  disableTabNode: true,
  disabledNodes: ['heading'],
})
```

| Option | Type | Default | Description |
| - | - | - | - |
| `disabledNodes` | `string[]` | `[]` | Node `type` values that cannot be indented, such as `'paragraph'`, `'heading'`, `'listitem'`, or `'quote'`. The indent controls are disabled for them, and the editor resets their indent to zero when another node is converted into one of these types. |
| `disableTabNode` | `boolean` | `false` | Makes Tab and Shift+Tab indent and outdent the block instead of inserting a tab character. Tab characters are also removed from pasted content. |

## Configure links

Restrict internal links by collection, set their maximum population depth, and add fields to the link drawer:

```ts theme={"theme":"tokyo-night"}
import { LinkFeature } from '@frogbotai/richtext-lexical'

LinkFeature({
  enabledCollections: ['pages', 'posts'],
  fields: ({ defaultFields }) => [
    ...defaultFields,
    {
      name: 'rel',
      type: 'select',
      options: ['noopener', 'noreferrer', 'nofollow'],
    },
  ],
  maxDepth: 2,
})
```

Set either `enabledCollections` or `disabledCollections`, not both. `disableAutoLinks: 'creationOnly'` prevents automatic creation while retaining updates to existing auto-links; `true` disables both.

| Option | Type | Default | Description |
| - | - | - | - |
| `enabledCollections` | `string[]` | Visible collections with `admin.enableRichTextLink` (on by default) | Collection slugs editors can link to internally. Replaces each collection's `admin.enableRichTextLink` setting. Cannot be combined with `disabledCollections`. |
| `disabledCollections` | `string[]` | None | Collection slugs excluded from internal links; every other collection is available. Replaces each collection's `admin.enableRichTextLink` setting. Cannot be combined with `enabledCollections`. |
| `fields` | `Field[] \| ({ config, defaultFields }) => Field[]` | Default link fields | Fields in the link drawer. An array replaces the default fields. A function receives the sanitized config and `defaultFields` (`text`, `linkType`, `url`, `doc` when internal links are available, and `newTab`) and returns the fields to use. Like any [field](https://docs.frogbot.ai/fields/overview.md), their `validate`, `defaultValue`, `filterOptions`, and `access` functions receive `req` with `req.frogbot`. |
| `maxDepth` | `number` | Remaining query depth | Maximum population depth of the internal link's `doc` field, regardless of the depth remaining when the link is reached. Applies only to the default `doc` field. |
| `disableAutoLinks` | `true \| 'creationOnly'` | Auto-links enabled | `'creationOnly'` stops URLs from becoming auto-links but keeps existing auto-links editable. `true` also removes auto-link support. |
| `internalDocToHref` | `({ linkNode }) => string` | None | Builds the URL for an internal link when converting to Markdown. Without it, internal links export with an empty URL, as `[text]()`. For JSX rendering, see [Internal links](https://docs.frogbot.ai/rich-text/converting-jsx.md#internal-links). |

## Configure relationships

```ts theme={"theme":"tokyo-night"}
import { RelationshipFeature } from '@frogbotai/richtext-lexical'

RelationshipFeature({
  disabledCollections: ['users'],
  maxDepth: 2,
})
```

Relationships can point to collections without uploads that keep `admin.enableRichTextRelationship` enabled (the default). `enabledCollections` and `disabledCollections` narrow that set further; set one or the other, not both.

| Option | Type | Default | Description |
| - | - | - | - |
| `enabledCollections` | `string[]` | All eligible collections | Only these eligible collections can be selected. |
| `disabledCollections` | `string[]` | None | These collections cannot be selected. |
| `maxDepth` | `number` | Remaining query depth | Maximum population depth of the related record, regardless of the depth remaining when the node is reached. |

## Configure files

The upload feature supports your upload collections, including the one marked [`file: true`](https://docs.frogbot.ai/upload/files). The example assumes your app declares a `files` collection. Fields configured for a collection are stored on that file node.

```ts theme={"theme":"tokyo-night"}
import { UploadFeature } from '@frogbotai/richtext-lexical'

UploadFeature({
  collections: {
    files: {
      fields: [
        { name: 'caption', type: 'text' },
        { name: 'alt', type: 'text' },
      ],
    },
  },
  enabledCollections: ['files'],
  maxDepth: 1,
})
```

Set either `enabledCollections` or `disabledCollections`, not both. `maxDepth` limits population of the referenced file itself; it does not limit fields stored directly on the file node.

File nodes can reference upload collections that keep `admin.enableRichTextRelationship` enabled (the default).

| Option | Type | Default | Description |
| - | - | - | - |
| `collections` | `{ [collectionSlug: string]: { fields: Field[] } }` | `{}` | Extra fields stored on file nodes that reference each upload collection. Editors fill them in from the file node's drawer. Like any [field](https://docs.frogbot.ai/fields/overview.md), their `validate`, `defaultValue`, `filterOptions`, and `access` functions receive `req` with `req.frogbot`. |
| `enabledCollections` | `string[]` | All eligible upload collections | Only these eligible upload collections can be selected. |
| `disabledCollections` | `string[]` | None | These upload collections cannot be selected. |
| `maxDepth` | `number` | Remaining query depth | Maximum population depth of the referenced file record, regardless of the depth remaining when the node is reached. |

## Configure toolbars

`InlineToolbarFeature` appears for selected text. `FixedToolbarFeature` stays visible and can follow whichever nested editor is focused.

```ts theme={"theme":"tokyo-night"}
import { FixedToolbarFeature } from '@frogbotai/richtext-lexical'

FixedToolbarFeature({
  applyToFocusedEditor: true,
  disableIfParentHasFixedToolbar: true,
})
```

`InlineToolbarFeature` takes no options.

| Option | Type | Default | Description |
| - | - | - | - |
| `applyToFocusedEditor` | `boolean` | `false` | Applies the toolbar to whichever editor is focused, including a nested editor inside a block, instead of only the editor that has this feature. |
| `disableIfParentHasFixedToolbar` | `boolean` | `false` | Hides this editor's fixed toolbar when a parent editor already shows one. |
| `customGroups` | `Record<string, Partial<ToolbarGroup>>` | None | Overrides for fixed-toolbar groups, keyed by group key. Each value is deep-merged into the matching group, commonly to change `order` or switch `type` between `'buttons'` and `'dropdown'`; `items` and `key` cannot be overridden. Values are sent to the browser, so they must be serializable. Built-in group keys are `add`, `text`, `align`, `indent`, `format`, and `features`. See [Toolbar groups](https://docs.frogbot.ai/rich-text/custom-features.md#toolbar-groups). |

## Configure blocks

`BlocksFeature` accepts block-level and inline block definitions. Each definition keeps its fields and optional JSX import/export behavior.

```ts theme={"theme":"tokyo-night"}
import { BlocksFeature } from '@frogbotai/richtext-lexical'

BlocksFeature({
  blocks: [
    {
      slug: 'callout',
      fields: [
        { name: 'title', type: 'text', required: true },
        { name: 'body', type: 'textarea' },
      ],
    },
  ],
  inlineBlocks: [
    {
      slug: 'badge',
      fields: [{ name: 'label', type: 'text', required: true }],
    },
  ],
})
```

See [Converting JSX](https://docs.frogbot.ai/rich-text/converting-jsx.md#lexical-blocks), [Converting HTML](https://docs.frogbot.ai/rich-text/converting-html.md#blocks-to-html), and [Converting Markdown](https://docs.frogbot.ai/rich-text/converting-markdown.md#defining-a-custom-block) to render blocks. Every `BlocksFeature` option is listed in [BlocksFeature options](https://docs.frogbot.ai/rich-text/blocks.md#blocksfeature-options).

`TreeViewFeature` adds an editor-state, DOM, and time-travel debugging panel. `TableFeature` adds table editing.

## Configure text state

`TextStateFeature` stores configured values under the serialized text node's `$` property. Keep the state map in a shared module so the editor and frontend converter use the same styles.

```ts theme={"theme":"tokyo-night"}
import { TextStateFeature, defaultColors } from '@frogbotai/richtext-lexical'

TextStateFeature({
  state: {
    color: {
      ...defaultColors.text,
      ...defaultColors.background,
      accent: {
        label: 'Accent',
        css: { color: 'var(--color-text-brand)' },
      },
    },
  },
})
```

| Option | Type | Default | Description |
| - | - | - | - |
| `state` | `{ [stateKey: string]: { [value: string]: { label: string; css: StyleObject } } }` | Required | Each top-level key is a text attribute, such as `color`. Its entries are the values editors can choose: `label` is shown in the toolbar and `css` holds the inline styles, written as hyphenated CSS property names, applied in the editor. A text node holds at most one value per key, so put mutually exclusive styles under the same key. `defaultColors.text` and `defaultColors.background` provide colors that work in light and dark themes. |

Lexical serializes text state under the text node's `$` key. Frontend rendering must map those stored state values back to the same CSS configuration. Keep the state object in an import-safe shared module and use it from both `TextStateFeature` and your custom JSX `text` converter.


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