> ## 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.

# Lexical Converters

> Convert Lexical rich text to JSX, HTML, Markdown, or plain text.

Rich Text fields store structured JSON. Use the converter that matches where the content will be consumed:

* [JSX](https://docs.frogbot.ai/rich-text/converting-jsx.md)
* [HTML](https://docs.frogbot.ai/rich-text/converting-html.md)
* [Markdown and MDX](https://docs.frogbot.ai/rich-text/converting-markdown.md)
* [Plain text](https://docs.frogbot.ai/rich-text/converting-plaintext.md)

## Retrieving the editor config

Some conversions need the sanitized editor configuration because enabled features define the available nodes and transformers. `editorConfigFactory` provides five ways to retrieve one.

```ts theme={"theme":"tokyo-night"}
import config from '@frogbot-config'

import {
  editorConfigFactory,
  lexicalEditor,
} from '@frogbotai/richtext-lexical'

type SanitizedRichTextField = Parameters<
  typeof editorConfigFactory.fromField
>[0]['field']

const field = {
  type: 'richText',
  editor: lexicalEditor({}),
} as const
```

Each method takes one object. This table lists every option and the methods that accept it:

| Option | Type | Default | Description |
| - | - | - | - |
| `config` | `FrogBotSanitizedConfig \| Promise<FrogBotSanitizedConfig>` | Required, except by `fromField` | The config returned by `buildConfig`, such as the `@frogbot-config` import. Throws if the value did not come from `buildConfig`. |
| `field` | `{ type: 'richText'; editor }` | Required by `fromField` and `fromUnsanitizedField` | The Rich Text field to read. `fromField` requires a sanitized editor and throws for an editor provider; `fromUnsanitizedField` requires an editor provider and throws otherwise. |
| `editor` | `ReturnType<typeof lexicalEditor>` | Required by `fromEditor` | The editor provider to build. |
| `features` | `FeatureProviderServer[] \| (args) => FeatureProviderServer[]` | Recommended defaults | `fromFeatures` only. Same as the `lexicalEditor` [`features` option](https://docs.frogbot.ai/rich-text/overview#editor-options). |
| `lexical` | `EditorConfig` | Built-in Lexical configuration | `fromFeatures` uses it as the `lexicalEditor` [`lexical` option](https://docs.frogbot.ai/rich-text/overview#editor-options). `fromEditor` accepts it but ignores it; the editor provider's own `lexical` option applies. |
| `isRoot` | `boolean` | `false` | `fromEditor`, `fromFeatures`, and `fromUnsanitizedField`. Builds the configuration as the root editor, so rich text fields nested in feature fields must set their own `editor`. |
| `parentIsLocalized` | `boolean` | `false` | Every method except `fromField`. Whether the field sits inside a localized field. |

Every method returns the sanitized editor config. `fromField` returns it directly; the others return a promise.

### Default editor config

Build the package's default feature set against your FrogBot config:

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

const editorConfig = await editorConfigFactory.default({ config })
```

### Config from a sanitized field

`fromField` is synchronous and accepts a Rich Text field whose editor has already been sanitized:

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

type SanitizedRichTextField = Parameters<
  typeof editorConfigFactory.fromField
>[0]['field']

export function configFromField(field: SanitizedRichTextField) {
  return editorConfigFactory.fromField({ field })
}
```

### Config from features

Build a configuration from a feature list without instantiating a reusable editor provider:

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

const editorConfig = await editorConfigFactory.fromFeatures({
  config,
  features: ({ defaultFeatures }) => [
    ...defaultFeatures,
    FixedToolbarFeature(),
  ],
})
```

This method also accepts `isRoot`, `lexical`, and `parentIsLocalized` options.

### Config from an editor provider

Use `fromEditor` when you already have a reusable editor provider:

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

const editor = lexicalEditor({
  features: ({ defaultFeatures }) => [
    ...defaultFeatures,
    FixedToolbarFeature(),
  ],
})

const editorConfig = await editorConfigFactory.fromEditor({
  config,
  editor,
})
```

Prefer `fromFeatures` when you only need the feature list. `fromEditor` also accepts `isRoot` and `parentIsLocalized`.

### Config from an unsanitized field

Use `fromUnsanitizedField` while you have a field with an editor provider rather than a sanitized adapter:

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

const field = {
  type: 'richText',
  editor: lexicalEditor({}),
} as const

const editorConfig = await editorConfigFactory.fromUnsanitizedField({
  config,
  field,
})
```

This method also accepts `isRoot` and `parentIsLocalized`.

### Read a sibling field config in a hook

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

type SanitizedRichTextField = Parameters<
  typeof editorConfigFactory.fromField
>[0]['field']

function isNamedSanitizedRichTextField(
  field: unknown,
  name: string,
): field is SanitizedRichTextField {
  return (
    typeof field === 'object' &&
    field !== null &&
    'name' in field &&
    field.name === name &&
    'type' in field &&
    field.type === 'richText' &&
    'editor' in field
  )
}

export const Articles: CollectionConfig = {
  slug: 'articles',
  fields: [
    {
      name: 'summary',
      type: 'text',
      hooks: {
        afterRead: [
          (args) => {
            const siblingFields =
              'siblingFields' in args && Array.isArray(args.siblingFields)
                ? args.siblingFields
                : []
            const field = siblingFields.find(
              (candidate) => isNamedSanitizedRichTextField(candidate, 'content'),
            )

            if (!field) {
              return args.value
            }

            const editorConfig = editorConfigFactory.fromField({ field })

            return args.value
          },
        ],
      },
    },
    {
      name: 'content',
      type: 'richText',
      editor: lexicalEditor({}),
    },
  ],
}
```


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