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

# Rendering on demand (Experimental)

> Render a FrogBot rich text editor from a client component.

`RenderLexical` lets a Client Component request and render a rich text field while preserving nested field schemas for blocks, links, files, tables, and drawers. It uses the Admin Panel's server functions, so render it within the Admin Panel rather than as a standalone editor on a public page.

> [!WARNING]
>
> `RenderLexical` and its server rendering function are experimental and may
> change in minor releases.

## Use an existing form

When the component is rendered inside a FrogBot form, omit `value` and `setValue`. The editor then writes to the form path identified by `name`, or by `path` when you explicitly override it. Saving the surrounding form persists that value normally.

This component renders an editor at the `previewContent` form path while using the configured `content` rich text field as its schema. Because `name` already matches the JSON field's form path, no `path` override is needed:

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

import type { DefaultNodeTypes } from '@frogbotai/richtext-lexical'
import { buildEditorState, RenderLexical } from '@frogbotai/richtext-lexical/client'
import type { JSONFieldClientProps } from 'frogbot'

export const PreviewContentField = (_props: JSONFieldClientProps) => {
  return (
    <RenderLexical
      initialValue={buildEditorState<DefaultNodeTypes>({
        text: 'Start writing.',
      })}
      name="previewContent"
      schemaPath="collection.posts.content"
    />
  )
}
```

Configure both the schema field and the form-backed JSON field on the collection. Component paths are resolved from your configured import-map base directory; see [Component paths](https://docs.frogbot.ai/custom-components/overview.md#component-paths).

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

export const Posts: CollectionConfig = {
  slug: 'posts',
  fields: [
    {
      name: 'content',
      type: 'richText',
      editor: lexicalEditor({}),
    },
    {
      name: 'previewContent',
      type: 'json',
      admin: {
        components: {
          Field: '/components/PreviewContentField#PreviewContentField',
        },
      },
    },
  ],
}
```

`RenderLexical` accepts these props. Note that `schemaPath` selects the schema, while `name` and `path` decide where the value is stored:

| Prop | Type | Default | Description |
| - | - | - | - |
| `schemaPath` | `string` | Required | Locates an existing configured rich text field so the server can load its features and nested schemas. Format: `collection.<collectionSlug>.<fieldPath>`. Throws if no field exists at that path. |
| `name` | `string` | The schema field's name | Name of the rendered field and its default form path. It does not select the schema. |
| `path` | `string` | `name` | Overrides the value path in the current form. Omit it when `name` is already the correct path. |
| `label` | `string \| Record<string, string> \| false` | The schema field's label | Label shown above the editor. Use an object keyed by locale for translations, or `false` to hide it. |
| `initialValue` | `unknown` | None | Value the server renders the editor with, so nested blocks can render without extra requests. |
| `value` | `DefaultTypedEditorState` | None | Controlled editor state. When `value` or `setValue` is set, the component manages its own value instead of using the surrounding form. |
| `setValue` | `(value: unknown, disableModifyingForm?: boolean) => void` | None | Called with the new editor state on every change in controlled mode. |
| `Loading` | `ReactElement` | Shimmer placeholder | Rendered while the editor is being fetched from the server. |
| `field` | `Partial<LexicalRichTextField>` | None | Deprecated. Use `name` and `label` instead; `field.name` and `field.label` are used only when those props are not set. |

The editor is always rendered visible, even when the schema field is hidden. The current user must be signed in and allowed to access the Admin Panel.

The schema path format is `collection.<collectionSlug>.<fieldPath>`. A top-level field uses `collection.posts.content`; a field nested in a group uses a path such as `collection.posts.layout.content`.

## Control the value yourself

Pass `value` and `setValue` when the surrounding component owns the editor state. This mode does not register the value with a FrogBot form and does not save it to the database. Persist it explicitly through an API operation if it should outlive the component.

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

import type { DefaultNodeTypes } from '@frogbotai/richtext-lexical'
import { buildEditorState, RenderLexical } from '@frogbotai/richtext-lexical/client'
import { useState } from 'react'
import type { ComponentProps } from 'react'

const createInitialValue = () =>
  buildEditorState<DefaultNodeTypes>({ text: 'Start writing.' })

export function ControlledEditor() {
  const [value, setValue] = useState<
    ComponentProps<typeof RenderLexical>['value']
  >(createInitialValue)

  const isEditorValue = (
    v: unknown,
  ): v is ComponentProps<typeof RenderLexical>['value'] =>
    v === undefined || (typeof v === 'object' && v !== null)

  const updateValue: NonNullable<
    ComponentProps<typeof RenderLexical>['setValue']
  > = (nextValue) => {
    if (isEditorValue(nextValue)) {
      setValue(nextValue)
    }
  }

  return (
    <div>
      <RenderLexical
        label="Draft content"
        name="draftContent"
        schemaPath="collection.posts.content"
        setValue={updateValue}
        value={value}
      />

      <button onClick={() => setValue(createInitialValue())} type="button">
        Reset editor
      </button>
    </div>
  )
}
```

Resetting changes only the controlled React state. It does not update a record unless your component separately sends the new value to FrogBot.

## Use a dedicated schema anchor

If the reusable editor needs a schema that is difficult to address inside arrays or blocks, define a hidden top-level rich text field as its schema anchor:

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

{
  name: 'onDemandEditorSchema',
  type: 'richText',
  editor: lexicalEditor({}),
  admin: {
    hidden: true,
  },
}
```

Use `schemaPath="collection.posts.onDemandEditorSchema"`. The anchor determines editor features and nested schemas; it does not determine where a form-backed or controlled value is stored.


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