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

# Converting JSX

> Render Lexical rich text as React JSX.

## Rich Text to JSX

Import `RichText` from the React subpath and pass it a serialized editor state:

```tsx theme={"theme":"tokyo-night"}
import type { SerializedEditorState } from '@frogbotai/richtext-lexical/lexical'
import { RichText } from '@frogbotai/richtext-lexical/react'

export function ArticleBody({ data }: { data: SerializedEditorState }) {
  return <RichText data={data} />
}
```

The component includes converters for standard nodes. Fetch enough relationship depth to populate links and file nodes before rendering them.

| Prop | Type | Default | Description |
| - | - | - | - |
| `data` | `SerializedEditorState` | Required | The rich text value to render. An empty editor state renders an empty wrapping `div`; a missing value renders nothing. |
| `converters` | `JSXConverters \| ({ defaultConverters }) => JSXConverters` | Built-in converters | Converters keyed by node type, with custom blocks under `blocks` and `inlineBlocks` keyed by slug, and an optional `unknown` fallback. An object replaces the built-in converters entirely; a function receives them as `defaultConverters` so you can extend them. |
| `nodeMap` | `LexicalEditorNodeMap` | None | A view's node map, such as `postViews.preview.nodes`. Its entries override `converters` for the same node type or block slug. See [Views](https://docs.frogbot.ai/rich-text/views.md#reuse-a-view-on-the-frontend). |
| `className` | `string` | Built-in class name | Class name of the wrapping `div`. |
| `disableContainer` | `boolean` | `false` | Renders the content without the wrapping `div`. |
| `disableIndent` | `boolean \| string[]` | `false` | Omits indentation styles. `true` disables them for every node; an array disables them for the listed node types. |
| `disableTextAlign` | `boolean \| string[]` | `false` | Omits text-alignment styles. `true` disables them for every node; an array disables them for the listed node types. |

The JSX converter requires fully populated values for nodes such as files.
Increase the query depth when those values are still record IDs.

## Internal links

FrogBot cannot infer your application's route for a linked record. Add `LinkJSXConverter` with an `internalDocToHref` function:

```tsx theme={"theme":"tokyo-night"}
import type {
  DefaultNodeTypes,
  SerializedLinkNode,
} from '@frogbotai/richtext-lexical'
import type { SerializedEditorState } from '@frogbotai/richtext-lexical/lexical'
import {
  type JSXConvertersFunction,
  LinkJSXConverter,
  RichText,
} from '@frogbotai/richtext-lexical/react'

const internalDocToHref = ({ linkNode }: { linkNode: SerializedLinkNode }) => {
  const { relationTo, value } = linkNode.fields.doc!

  if (typeof value !== 'object') {
    throw new Error('Expected a populated internal link')
  }

  if (relationTo === 'pages') {
    return `/${value.slug}`
  }

  return `/${relationTo}/${value.slug}`
}

const converters: JSXConvertersFunction<DefaultNodeTypes> = ({
  defaultConverters,
}) => ({
  ...defaultConverters,
  ...LinkJSXConverter({ internalDocToHref }),
})

export function ArticleBody({ data }: { data: SerializedEditorState }) {
  return <RichText<DefaultNodeTypes> converters={converters} data={data} />
}
```

`LinkJSXConverter` returns converters for the `link` and `autolink` node types.

| Option | Type | Default | Description |
| - | - | - | - |
| `internalDocToHref` | `({ linkNode }) => string` | None | Returns the URL for an internal link from its serialized node; the linked record is in `linkNode.fields.doc`. Without it, internal links render with `href="#"` and an error is logged. |

## Lexical blocks

Custom blocks need converters keyed by block slug:

```tsx theme={"theme":"tokyo-night"}
'use client'

import type {
  DefaultNodeTypes,
  SerializedBlockNode,
  SerializedInlineBlockNode,
} from '@frogbotai/richtext-lexical'
import type { SerializedEditorState } from '@frogbotai/richtext-lexical/lexical'
import {
  type JSXConvertersFunction,
  RichText,
} from '@frogbotai/richtext-lexical/react'

type BadgeBlock = {
  blockName?: string
  blockType: 'badge'
  label: string
}

type NumberBlock = {
  blockName?: string
  blockType: 'number'
  number: number
}

type TextBlock = {
  blockName?: string
  blockType: 'text'
  text: string
}

type NodeTypes =
  | DefaultNodeTypes
  | SerializedBlockNode<NumberBlock | TextBlock>
  | SerializedInlineBlockNode<BadgeBlock>

const converters: JSXConvertersFunction<NodeTypes> = ({
  defaultConverters,
}) => ({
  ...defaultConverters,
  blocks: {
    number: ({ node }) => <div>{node.fields.number}</div>,
    text: ({ node }) => <div>{node.fields.text}</div>,
  },
  inlineBlocks: {
    badge: ({ node }) => <span>{node.fields.label}</span>,
  },
})

export function ArticleBody({ data }: { data: SerializedEditorState }) {
  return <RichText converters={converters} data={data} />
}
```

## Override a converter

Return a converter under the standard node key to replace its default rendering. This example renders file images with `next/image`:

```tsx theme={"theme":"tokyo-night"}
'use client'

import type {
  DefaultNodeTypes,
  SerializedUploadNode,
} from '@frogbotai/richtext-lexical'
import type { SerializedEditorState } from '@frogbotai/richtext-lexical/lexical'
import {
  type JSXConvertersFunction,
  RichText,
} from '@frogbotai/richtext-lexical/react'
import Image from 'next/image'

const converters: JSXConvertersFunction<DefaultNodeTypes> = ({
  defaultConverters,
}) => ({
  ...defaultConverters,
  upload: ({ node }: { node: SerializedUploadNode }) => {
    const file = node.value

    if (node.relationTo !== 'files' || !file || typeof file !== 'object' || !file.url) {
      return null
    }

    return (
      <Image
        alt={file.alt ?? ''}
        height={file.height ?? 0}
        src={file.url}
        width={file.width ?? 0}
      />
    )
  },
})

export function ArticleBody({ data }: { data: SerializedEditorState }) {
  return <RichText converters={converters} data={data} />
}
```


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