Skip to main content
Custom components let you render your own React UI inside Webchat. Instead of being limited to text, images, and carousels, you can build any visual element and have either your code or the LLM send it to users. There are two ways to use custom components:
  1. Direct send - your handler explicitly sends the component
  2. LLM-driven - the LLM decides when to render the component during execute()

Creating a component

A custom component has two files: a React component (.bp.tsx) and an ADK wrapper (.ts).

Step 1: Write the React component

Create a .bp.tsx file in src/components/:
You can use inline styles or import .css files directly. CSS imports are bundled and injected as <style> tags at runtime. React 18 is available with hooks like useState, useMemo, and useEffect.

Step 2: Create the ADK wrapper

Create a .ts file next to the .bp.tsx:
The component is now discoverable by adk dev and adk deploy. The component name is derived from the React function name (TicketCard in this case).

Sending components manually

Send a custom component like any other message:
The props object is type-checked against the React component’s Props type.

LLM-driven components

To let the LLM decide when to render your component, add LLM metadata and list it in the conversation’s components array.

Add LLM metadata

The description field tells the LLM what the component does:
TicketCard.ts

Provide the component to the LLM

To provide the component to your agent’s LLM, pass it into the execute() function’s components field:
The LLM now knows about <TicketCard> and will render it when appropriate during execute().
If you list a component in components that was created without LLM metadata, the Conversation constructor throws immediately.

Combining both approaches

You can use direct send and LLM-driven components in the same conversation:
WelcomeBannerComponent doesn’t need LLM metadata since it’s only sent directly. It’s not in the components array.

Build pipeline

During adk dev and adk deploy, custom components go through the following pipeline:
  1. Discover - scans src/ for .ts files that export CustomComponent instances
  2. Resolve - finds the .bp.tsx import in each wrapper
  3. Bundle - esbuild bundles the .bp.tsx into standalone ESM (react and react-dom are externalized)
  4. Upload - the bundle is uploaded to Botpress as a public file
  5. Wire - the component URL is injected so conversation.send() works
During adk dev, the file watcher rebuilds only changed components incrementally.

Tips

  • Keep components focused. One component, one purpose. A ticket card, a status badge, a product listing.
  • Use useMemo for expensive computations or random values. React may re-render multiple times.
  • Name your component function. The name is derived from the function name. Anonymous exports become "UnnamedComponent".
  • Write good descriptions. The LLM reads the description field to decide when to use the component.
  • Provide realistic examples. Use values that represent real usage, not placeholders like "string".
  • Avoid reserved prop names. The webchat renderer reserves status. Use more specific names like ticketStatus.

Limitations

  • Webchat only. Custom components only render in Webchat. Other channels don’t support them.
  • No global stylesheets. You can import .css files in your component, but your project’s global styles are not available.
  • React 18. React 19 features are not available.
  • No server-side rendering. Components are client-rendered in the browser.

Troubleshooting

Last modified on April 27, 2026