How to Register React Components for LLM Use with Tambo AI
Tambo AI enables large language models to render React UI by exposing components through a runtime registry that validates metadata, converts props schemas to JSON-Schema, and provides registration APIs via the TamboRegistryProvider.
Tambo AI is an open-source React SDK that bridges the gap between conversational AI and interactive user interfaces. To register React components for LLM use, developers define component metadata with typed props schemas and pass them through the SDK's validation pipeline, which prepares the components for AI-driven rendering at runtime.
The Component Registration Pipeline
The registration flow consists of three distinct stages that transform a React component into an LLM-accessible UI element:
- Definition – Describe the component with metadata, props schema, and optional loading states
- Validation – Verify the schema, convert it to JSON-Schema, and check for forbidden types
- Storage – Add the validated component to the runtime registry and associate any tools
This pipeline is implemented across react-sdk/src/model/component-metadata.ts, react-sdk/src/util/registry-validators.ts, and react-sdk/src/providers/tambo-registry-provider.tsx.
Step 1: Define a TamboComponent with Props Schema
Components must conform to the TamboComponent interface defined in react-sdk/src/model/component-metadata.ts. This structure requires a name, description, the React component itself, an optional loadingComponent, and a props schema.
The propsSchema accepts Zod, Valibot, or similar schema definitions, which the SDK converts to JSON-Schema for the LLM:
// src/components/MyButton.tsx
import { TamboComponent } from "@tambo-ai/react";
import { z } from "zod";
export const myButton: TamboComponent = {
name: "MyButton",
description: "A simple button used in chat UI that triggers an action when clicked",
component: (props: { label: string; onClick: () => void }) => (
<button onClick={props.onClick}>{props.label}</button>
),
loadingComponent: () => <div>Loading button…</div>,
propsSchema: z.object({
label: z.string().describe("The text displayed on the button"),
onClick: z.function().describe("Callback fired when the button is clicked"),
}),
};
The propsSchema is mandatory. If omitted, the validation step will throw an error preventing registration.
Step 2: Validate and Prepare the Component
Before a component enters the registry, validateAndPrepareComponent in react-sdk/src/util/registry-validators.ts performs several critical checks:
- Name validation – Ensures the component name is unique and follows naming conventions
- Schema conversion – Transforms Zod/Valibot schemas into standard JSON-Schema using internal converters
- Type restrictions – Forbids record types (
Record<string, any>) in props schemas to prevent ambiguous LLM outputs - Deprecation handling – Migrates legacy
propsDefinitionto the modernpropsSchemaformat
If validation fails, the function throws immediately, preventing malformed components from reaching the LLM context window.
Step 3: Register Components at Runtime
The TamboRegistryProvider in react-sdk/src/providers/tambo-registry-provider.tsx maintains the component registry as React state (componentList). It exposes the registerComponent function through the TamboRegistryContext, which developers can access via the useTambo hook.
Static Registration via Provider
For applications with known component sets, pass an array to the components prop:
import { TamboRegistryProvider } from "@tambo-ai/react";
import { myButton } from "./components/MyButton";
import { dataCard } from "./components/DataCard";
export default function App() {
return (
<TamboRegistryProvider components={[myButton, dataCard]}>
<YourApp />
</TamboRegistryProvider>
);
}
The provider registers these components once during mount using a useEffect hook.
Dynamic Registration via Hook
For lazy-loaded or conditional components, use the useTambo hook:
import { useTambo } from "@tambo-ai/react";
import { useEffect, useCallback } from "react";
import { myButton } from "@/components/MyButton";
export function ChatInterface() {
const { registerComponent } = useTambo();
const doRegister = useCallback(() => {
registerComponent(myButton, false); // false suppresses overwrite warnings
}, [registerComponent]);
useEffect(() => {
doRegister();
}, [doRegister]);
return <div>Chat interface with LLM-rendered components</div>;
}
Tool Associations
Components can bundle related tools using the associatedTools property. When registered, the provider automatically calls registerTools and updates componentToolAssociations state, creating a bidirectional mapping between components and their capabilities:
const myButton: TamboComponent = {
name: "MyButton",
// ... other properties
associatedTools: [fetchUserDataTool, updateStatusTool],
};
How the LLM Discovers Registered Components
The SDK serializes the registry for LLM consumption via react-sdk/src/v1/utils/registry-conversion.ts. The toAvailableComponents function converts the internal ComponentRegistry map into a JSON payload containing component names, descriptions, and JSON-Schema definitions for props:
// Simplified from registry-conversion.ts
export const toAvailableComponents = (registry: ComponentRegistry) => {
return Object.values(registry).map((component) => ({
name: component.name,
description: component.description,
propsSchema: component.props, // JSON-Schema format
}));
};
This payload is sent to the Tambo AI server with each message, allowing the LLM to select appropriate components by name and generate valid props that conform to the schema.
Summary
- Tambo AI exposes React components to LLMs through a runtime registry system defined in
react-sdk/src/providers/tambo-registry-provider.tsx. - Component definitions require a
TamboComponentinterface withname,description,component, andpropsSchema(Zod/Valibot supported). - Validation occurs in
react-sdk/src/util/registry-validators.ts, which converts schemas to JSON-Schema and forbids ambiguous record types. - Registration can be static via
TamboRegistryProvideror dynamic via theuseTambohook, with optionalassociatedToolsfor component-tool binding. - LLM discovery happens through serialization in
react-sdk/src/v1/utils/registry-conversion.ts, sending JSON-Schema metadata to the AI for component selection.
Frequently Asked Questions
What schema libraries does Tambo AI support for component props?
Tambo AI accepts Zod, Valibot, and similar schema definition libraries through the propsSchema property. The validateAndPrepareComponent function in react-sdk/src/util/registry-validators.ts automatically converts these schemas to standard JSON-Schema format before sending them to the LLM, ensuring compatibility with the AI's structured output capabilities.
Can I register components dynamically after the app has mounted?
Yes, you can register components dynamically using the useTambo hook. The hook exposes the registerComponent function from the TamboRegistryContext, allowing you to add components inside useEffect hooks or event handlers. Pass false as the second argument to suppress console warnings when overwriting existing component registrations during hot reloading or iterative updates.
How does Tambo AI associate tools with specific components?
Components can declare associatedTools in their TamboComponent definition. When registerComponent detects these tools, it automatically calls registerTools and updates the internal componentToolAssociations state map. This creates a bidirectional relationship where the LLM knows which tools are available for specific UI components, and the system can route tool calls to the appropriate component context.
What happens if a component's props schema uses TypeScript record types?
The validation layer in react-sdk/src/util/registry-validators.ts explicitly forbids record types (Record<string, any>) in props schemas. If detected, validateAndPrepareComponent will throw an error preventing registration. This restriction prevents ambiguous type definitions that could confuse the LLM's structured output generation, ensuring that all props can be accurately described by JSON-Schema.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →