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

# Swap in your own React components

FrogBot lets you replace or extend parts of the [Admin Panel](https://docs.frogbot.ai/admin/admin-navigation.md) with your own React components. Custom Components are React Server Components by default, so they can use the [Local API](https://docs.frogbot.ai/local-api/overview.md) without a separate HTTP request.

> [!NOTE]
>
> Client Components are supported. Add the `'use client'` directive to the file.
> FrogBot removes non-serializable default props before rendering it.

FrogBot supports Custom Components in these scopes:

* [Root Components](https://docs.frogbot.ai/custom-components/root-components.md)
* [Collection Components](https://docs.frogbot.ai/configuration/collections.md#custom-components)
* [Field Components](https://docs.frogbot.ai/configuration/collections.md#fields)

## Defining Custom Components

Custom Components are registered in your FrogBot config using [Component Paths](#component-paths). FrogBot uses the path to replace a built-in component or render your component in an available slot.

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

export default buildConfig({
  admin: {
    components: {
      actions: ['/components/StatusAction#StatusAction'],
    },
  },
})
```

### Component Paths

Components are referenced by path instead of being imported into the config. FrogBot detects the source directory: `src` when present, otherwise the project root. For example, `/components/StatusAction` resolves to `src/components/StatusAction` in the blank template.

Append `#ExportName` for a named export. Omit it for a default export. You can also use an object with `path` and `exportName`.

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

export default buildConfig({
  admin: {
    components: {
      actions: [
        '/components/StatusAction#StatusAction',
        '/components/DefaultAction',
        {
          path: '/components/ReviewAction',
          exportName: 'ReviewAction',
        },
      ],
    },
  },
})
```

### Component Config

An object component reference can pass custom props alongside its path:

```ts theme={"theme":"tokyo-night"}
export default buildConfig({
  admin: {
    components: {
      actions: [
        {
          path: '/components/StatusAction',
          exportName: 'StatusAction',
          clientProps: {
            label: 'Review status',
          },
          serverProps: {
            collection: 'posts',
          },
        },
      ],
    },
  },
})
```

| Option | Type | Default | Description |
| - | - | - | - |
| `path` | `string` | Required | Path to the component file, resolved like a string [Component Path](#component-paths). It may include `#ExportName`. |
| `exportName` | `string` | The name after `#` in `path`, otherwise `'default'` | Named export to load from `path`. Takes precedence over a `#ExportName` in `path`. |
| `clientProps` | `object` | None | Props passed to the component, overriding slot props with the same name. Values must be serializable when the component is a Client Component. |
| `serverProps` | `object` | None | Props passed only when the component is a Server Component, overriding slot server props with the same name. They may contain server-only values. |

### Import Map

FrogBot generates an import map that resolves every configured Component Path. It regenerates the map when the application starts and during development updates. You can regenerate it manually with:

```bash theme={"theme":"tokyo-night"}
pnpm frogbot generate:importmap
```

> [!WARNING]
>
> Do not edit the generated import map. Change the component path in your config
> and regenerate it instead.

Plugin authors register public component paths in supported slots. Import helper components directly from the component module that renders them. The public `admin.importMap` option controls `autoGenerate`; see [Import map options](https://docs.frogbot.ai/admin/overview.md#import-map-options). `baseDir` and `admin.dependencies` are not supported authoring options.

## Building Custom Components

### Server Components

Server Components can use the FrogBot instance attached to the request. Component-specific types describe the props and the request location:

```tsx theme={"theme":"tokyo-night"}
import type { TextFieldServerProps } from 'frogbot'

export const RelatedPostCount = async ({ req }: TextFieldServerProps) => {
  const result = await req.frogbot.count({
    collection: 'posts',
    overrideAccess: false,
    req,
  })

  return <p>{result.totalDocs} posts</p>
}
```

The exact props depend on the component slot. Use the exported type for the field, view, or slot you are implementing.

### Custom Props

Client props must be serializable. Server props may contain server-only values when the receiving component remains a Server Component.

```tsx theme={"theme":"tokyo-night"}
import Link from 'next/link'

export function StatusAction({ label }: { label: string }) {
  return <Link href="/collections/posts">{label}</Link>
}
```

### Client Components

Add `'use client'` when a component needs state, effects, event handlers, or FrogBot's client hooks:

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

import { useState } from 'react'

import { Button } from '@frogbotai/ui'

export function Counter() {
  const [count, setCount] = useState(0)

  return <Button onClick={() => setCount(count + 1)}>Clicked {count} times</Button>
}
```

> [!WARNING]
>
> Props crossing from a Server Component to a Client Component must be
> serializable.

### Accessing Config

Server Components can read the sanitized config from `req.frogbot.config`. Client Components receive a serializable client config through `useConfig`:

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

import { useConfig } from '@frogbotai/ui/admin'

export function ServerLink() {
  const {
    config: { serverURL },
  } = useConfig()

  return <a href={serverURL}>Home</a>
}
```

Field components receive their field config as `field`: authored configuration on the server and serializable configuration on the client. Server field components also receive `clientField` for passing serializable configuration to a client component.

```tsx theme={"theme":"tokyo-night"}
import type { TextFieldServerProps } from 'frogbot'

export const FieldName = ({ field }: TextFieldServerProps) => {
  return <p>Field name: {field.name}</p>
}
```

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

import type { TextFieldClientProps } from 'frogbot'

export const ClientFieldName = ({ field }: TextFieldClientProps) => {
  return <p>Field name: {field.name}</p>
}
```

### Rendering Component Slots

Use `RenderCustomComponent` to choose between an already-rendered React node and a fallback. It does not resolve component paths. An `undefined` node uses the fallback; `null` renders nothing.

```tsx theme={"theme":"tokyo-night"}
import { RenderCustomComponent } from '@frogbotai/ui/admin'
import type { ReactNode } from 'react'

export function ComponentSlot({ content }: { content?: ReactNode }) {
  return <RenderCustomComponent CustomComponent={content} Fallback={<p>No content</p>} />
}
```

### Translations and Locale

Client Components can read the current language and locale with `useTranslation` and `useLocale`:

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

import { useLocale, useTranslation } from '@frogbotai/ui/admin'

export function LocaleStatus() {
  const locale = useLocale()
  const { i18n } = useTranslation()

  return <p>{i18n.language} / {locale.code}</p>
}
```

See [Internationalization](https://docs.frogbot.ai/configuration/i18n.md) and [Localization](https://docs.frogbot.ai/configuration/localization.md) for configuration details.

### Using Hooks

FrogBot's curated `@frogbotai/ui/admin` entry exposes hooks that share the Admin Panel's contexts. Import them from that entry:

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

import { useDocumentInfo, useFormFields } from '@frogbotai/ui/admin'

export function DocumentStatus() {
  const { collectionSlug } = useDocumentInfo()
  const title = useFormFields(([fields]) => fields.title?.value)

  return <p>{collectionSlug}: {String(title ?? 'Untitled')}</p>
}
```

Use `useFormFields` with a selector instead of subscribing to the entire form when you only need specific values.

### Adding Styles

Import a CSS file from your component:

```tsx theme={"theme":"tokyo-night"}
import './StatusAction.css'

export function StatusAction() {
  return <div className="status-action">Ready for review</div>
}
```

FrogBot UI components and theme tokens are available in every admin component without a wrapper and follow the admin's light and dark theme. Use the admin's semantic [color tokens](https://docs.frogbot.ai/chat/ui-theming.md#color-tokens), such as `--color-bg-secondary`, `--color-border` and `--color-text`; they switch with the theme.

Your component CSS beats FrogBot's styles as long as it isn't in a CSS layer. See [override FrogBot styles](https://docs.frogbot.ai/chat/ui-theming.md#override-frogbot-styles) and [admin panel styles](https://docs.frogbot.ai/chat/ui-theming.md#admin-panel-styles).

```css theme={"theme":"tokyo-night"}
.status-action {
  background: var(--color-bg-secondary);
  border: 1px solid var(--color-border);
  color: var(--color-text);
  padding: 0.75rem 1rem;
}
```

### Tooltips

Wrap any element in `Tooltip` to label it on hover and keyboard focus. It looks like the admin's own tooltips, follows the theme, and moves to the opposite side when there isn't room:

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

import { Button, Tooltip } from '@frogbotai/ui'

export function ArchiveButton() {
  return (
    <Tooltip label="Archive this document" side="bottom">
      <Button variant="ghost">Archive</Button>
    </Tooltip>
  )
}
```

The child must accept a ref and pass on hover and focus events, as buttons, links and FrogBot UI components do. `Tooltip` also works inside another component's `asChild` trigger, such as a dropdown menu's.

| Option | Type | Default | Description |
| - | - | - | - |
| `label` | `ReactNode` | Required | The tooltip's text or content. |
| `children` | `ReactElement` | Required | The element the tooltip describes. |
| `side` | `'top' \| 'right' \| 'bottom' \| 'left'` | `'top'` | The side the tooltip prefers. |
| `delay` | `number` | `500` | Milliseconds to wait on hover before showing. |
| `open` | `boolean` | — | Shows or hides the tooltip yourself, instead of on hover and focus. |
| `disabled` | `boolean` | `false` | Never shows the tooltip, keeping `children` as they are. |
| `contentClassName` | `string` | — | Classes added to the tooltip bubble. |

Other props are passed to `children`. To restyle every tooltip, override the `.fb-tooltip` class in unlayered CSS, or set the tooltip [color tokens](https://docs.frogbot.ai/chat/ui-theming.md#color-tokens) `--color-bg-tooltip` and `--color-text-ontooltip`.

## Performance

Keep the server/client boundary narrow. Prefer Server Components, pass only the serializable values a Client Component needs, and avoid broad form subscriptions that cause unrelated updates to re-render your component.

Import Admin Panel hooks and curated UI components from the `@frogbotai/ui/admin` entry. Do not use deep element or icon imports.

If a hook returns an undefined context, confirm that the component is rendered inside the Admin Panel and that your application resolves one version of each FrogBot package. See [Troubleshooting](https://docs.frogbot.ai/troubleshooting/troubleshooting.md#dependency-mismatches).


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