Add Components to Registry
Convert existing React components into Tambo-registered components that AI can render.
Quick Start
# Point to a component file or folder /add-components-to-registry src/components/ProductCard.tsx /add-components-to-registry src/components/cards/
Workflow
- •Read component(s) - Analyze props, types, and purpose
- •Generate Zod schema - Create propsSchema from prop types
- •Write description - Help AI know when to use it
- •Add to registry - Update lib/tambo.ts
Step 1: Analyze Component
Read the component file and extract:
- •Component name
- •Props interface/type
- •What it renders (for description)
- •Optional vs required props
Example Input
// src/components/ProductCard.tsx
interface ProductCardProps {
name: string;
price: number;
imageUrl?: string;
onSale?: boolean;
rating?: number;
}
export function ProductCard({
name,
price,
imageUrl,
onSale,
rating,
}: ProductCardProps) {
return (
<div className="product-card">
{imageUrl && <img src={imageUrl} alt={name} />}
<h3>{name}</h3>
<p>
${price}
{onSale && " (On Sale!)"}
</p>
{rating && <span>★ {rating}/5</span>}
</div>
);
}
Step 2: Generate Zod Schema
Convert TypeScript types to Zod with .describe():
import { z } from "zod";
export const ProductCardSchema = z.object({
name: z.string().describe("Product name"),
price: z.number().describe("Price in dollars"),
imageUrl: z.string().optional().describe("Product image URL"),
onSale: z.boolean().optional().describe("Whether product is on sale"),
rating: z.number().optional().describe("Rating out of 5"),
});
Type Mapping
| TypeScript | Zod |
|---|---|
string | z.string() |
number | z.number() |
boolean | z.boolean() |
string[] | z.array(z.string()) |
"a" | "b" | z.enum(["a", "b"]) |
optional | .optional() |
Date | z.string().describe("ISO date string") |
Record<K,V> | z.record(z.string(), z.number()) |
Step 3: Write Description
The description tells AI when to render this component. Be specific:
// Bad: Too vague description: "Shows a product"; // Good: Tells AI when to use it description: "Displays a product with name, price, and optional image/rating. Use when user asks to see product details, browse items, or view catalog entries.";
Step 4: Add to Registry
// lib/tambo.ts
import { TamboComponent } from "@tambo-ai/react";
import { ProductCard } from "@/components/ProductCard";
import { ProductCardSchema } from "@/components/ProductCard.schema";
export const components: TamboComponent[] = [
{
name: "ProductCard",
component: ProductCard,
description:
"Displays a product with name, price, and optional image/rating. Use when user asks to see product details, browse items, or view catalog entries.",
propsSchema: ProductCardSchema,
},
// ... other components
];
Batch Registration
When given a folder, process all .tsx files:
src/components/cards/ ├── ProductCard.tsx → Register as "ProductCard" ├── UserCard.tsx → Register as "UserCard" ├── StatCard.tsx → Register as "StatCard" └── index.ts → Skip (barrel file)
Skip files that:
- •Are barrel exports (index.ts)
- •Don't export React components
- •Are test files (_.test.tsx, _.spec.tsx)
- •Are story files (*.stories.tsx)
Schema File Location
Place schemas next to components:
src/components/ ├── ProductCard.tsx ├── ProductCard.schema.ts # Zod schema ├── UserCard.tsx └── UserCard.schema.ts
Or in a dedicated schemas folder:
src/
├── components/
│ ├── ProductCard.tsx
│ └── UserCard.tsx
└── schemas/
├── ProductCard.schema.ts
└── UserCard.schema.ts
Handling Complex Props
Nested Objects
// TypeScript
interface Address {
street: string;
city: string;
zip: string;
}
interface Props {
address: Address;
}
// Zod
const AddressSchema = z.object({
street: z.string().describe("Street address"),
city: z.string().describe("City name"),
zip: z.string().describe("ZIP/postal code"),
});
const PropsSchema = z.object({
address: AddressSchema.describe("Shipping address"),
});
Callbacks (Skip)
Don't include callbacks in propsSchema - AI can't provide functions:
// TypeScript
interface Props {
name: string;
onClick: () => void; // Skip this
}
// Zod - only data props
const PropsSchema = z.object({
name: z.string().describe("Display name"),
// onClick omitted - AI provides data, not behavior
});
Children (Skip)
Don't include children - AI renders the component, doesn't compose it:
// Skip children prop in schema
Verification
After registration, verify in the chat:
"Show me a product card for a laptop priced at $999"
AI should render the ProductCard with appropriate props.