AI/TLDR

What Is Tambo? Generative UI SDK for React

You will understand how Tambo lets an agent choose which React components to render by registering them with Zod schemas, and how that differs from rendering plain text.

INTERMEDIATE11 MIN READUPDATED 2026-06-14

In plain English

Most AI chat features answer in plain text. You ask a question, the model writes a paragraph back, and that's it. But a sentence is a clumsy way to show a sales chart, a date picker, a shopping cart, or a list of editable tasks. Those are interfaces, not prose. Tambo is an open-source generative-UI SDK for React that lets your agent answer with actual React components instead of only words.

Tambo — illustration
Tambo — img.freepik.com

The trick is simple to describe. You hand Tambo a small catalogue of components you trust — a <SalesChart>, a <WeatherCard>, a <TaskBoard> — and you describe the shape of each one's props using a Zod schema. From then on, when a user types a request, the agent reads that catalogue, picks the component that fits, fills in its props, and Tambo renders it live in the conversation.

Think of a restaurant with a fixed menu. The kitchen (your app) decides exactly which dishes exist and how each one is made — that's safety. The waiter (the agent) listens to what the guest wants and chooses a dish from that menu, never inventing one off-book. The guest gets a real plate of food, not a written description of food. Tambo is the system that lets the waiter pick from your menu and serve a working dish, where each "dish" is an interactive React component.

Why it matters

Plain-text AI hits a wall the moment the right answer is something you do, not something you read. Tambo exists to close that gap, and it solves three real problems for anyone building an AI feature into a product.

  • Some answers are interfaces. "Show me revenue by region" deserves a chart you can hover, not a wall of numbers. "Book a table" deserves a date picker, not a back-and-forth typing dance. Returning a component makes the answer usable in one step.
  • Your components stay in control. Because the agent can only render components you registered, your design system, styling, and behaviour are preserved. The model fills in props; it never writes raw HTML or invents UI you didn't approve. That's a much safer boundary than letting a model emit free-form markup.
  • One agent, many surfaces. Instead of hard-coding which screen appears for which intent, you register a set of components once and let the agent route requests to the right one. Adding a new capability often means registering one more component, not wiring a new branch of UI logic.

Who cares? Builders of AI assistants, internal copilots, dashboards, and "chat with your app" features — anyone whose users ask for things that are better shown than told. If your AI feature today just streams paragraphs, and you keep wishing it could pop up a real control, that's exactly the itch generative UI scratches. Tambo is one of the emerging tools in this space, alongside broader patterns covered in generative UI patterns.

How it works

Under the hood, Tambo turns your registered components into tools the model can call. A model that supports tool/function calling already knows how to choose a tool and produce arguments that match a schema. Tambo reuses that exact machinery: each component's Zod schema becomes a tool definition, the component itself is what gets rendered when that "tool" is chosen, and the props are the arguments.

The register-then-pick flow

There are two phases. Setup happens once: you describe your component catalogue. Runtime happens on every message: the agent picks a component and Tambo renders it. The catalogue is the contract that makes the whole thing safe — the model is choosing from your list, never improvising.

The Zod schema does double duty. It tells the model what arguments are valid (so it can fill them correctly), and it validates what comes back before your component ever renders, so a malformed response is caught instead of crashing the UI. Schema-first is the safety rail of the whole pattern.

registering a component with a Zod schematypescript
import { z } from "zod";
import { SalesChart } from "./SalesChart";

// Describe the props the agent is allowed to fill.
export const salesChartSchema = z.object({
  region: z.string().describe("e.g. 'EMEA' or 'all'"),
  metric: z.enum(["revenue", "units"]),
});

// The catalogue: each entry pairs a component with its schema
// and a short description the model uses to decide when to pick it.
export const components = [
  {
    name: "SalesChart",
    description: "Show a bar chart of sales for a region.",
    component: SalesChart,
    propsSchema: salesChartSchema,
  },
];

You wrap your app in a provider and pass the catalogue in. A hook then exposes the conversation — the messages, the streaming state, and the rendered components — so your chat surface stays a normal React tree.

wiring it into a React apptypescript
import { TamboProvider, useTambo } from "@tambo-ai/react";
import { components } from "./components";

function App() {
  return (
    <TamboProvider apiKey={process.env.TAMBO_API_KEY} components={components}>
      <Chat />
    </TamboProvider>
  );
}

function Chat() {
  // messages can now contain rendered components, not just text
  const { thread } = useTambo();
  return <MessageList messages={thread.messages} />;
}

Tambo distinguishes two kinds of components. Generative components render once as part of a response — a chart, a summary card, a result you read and move on from. Interactable components persist and update across turns — a task board you keep editing, a cart the user refines by saying "add two more." The interactable kind is what lets a conversation drive a small app, not just emit one-shot widgets.

A worked example: "sales by region"

Walk one request end to end. A user types "Show me revenue by region for EMEA." Here is what happens, step by step, in a Tambo-powered app.

  1. Match intent to a tool. The agent reads your catalogue and its descriptions. "Show a bar chart of sales for a region" fits, so it selects SalesChart over, say, a TaskBoard.
  2. Generate props. Guided by the Zod schema, it produces { region: "EMEA", metric: "revenue" }. The schema constrains it: metric must be one of the allowed values, so the model can't pass "profit" by mistake.
  3. Validate. Tambo checks those props against the schema before rendering. If validation fails, the bad response is caught rather than handed to your component.
  4. Render. Your real <SalesChart region="EMEA" metric="revenue" /> mounts inside the conversation, fetching and drawing data exactly as it would anywhere else in your app.
  5. Interact. Because the chart is a normal component, the user can hover bars, toggle a legend, or follow up with "now show units," which the agent turns into a new prop set.

Tambo vs other generative-UI approaches

Tambo is one point on a spectrum of ways to get UI out of an AI. It helps to see what it is not, so you pick the right tool.

A common comparison is Tambo vs CopilotKit. Both are open-source and both can render generative UI, but their centre of gravity differs. CopilotKit is a broad frontend stack for building agent-native apps — chat surfaces, shared state, human-in-the-loop, and an agent-to-UI protocol — across several frameworks. Tambo is narrower and more focused: its defining idea is model-chosen, schema-bound React components. If your need is precisely "let the agent pick from my typed component set," Tambo expresses that directly; if you want a fuller copilot platform, a stack like CopilotKit covers more ground.

QuestionTambo's answer
Who decides which UI shows?The agent, from your registered set
Who defines the components?You, as normal React + Zod
Can the model invent new UI?No — only your catalogue, validated by schema
Open-source?Yes, MIT-licensed
Framework?React

Common pitfalls

Generative UI is fun to demo and easy to get subtly wrong. Most trouble comes from the catalogue and the schemas, not the model.

  • Vague component descriptions. The agent picks a component largely from your one-line description. If two components sound alike ("show data" vs "display data"), it will mix them up. Write descriptions that say when to use each one, not just what it is.
  • Loose schemas. A prop typed as a bare string lets the model pass anything. Use enums, ranges, and .describe() so the schema both guides generation and rejects nonsense. Tight schemas are your validation safety net.
  • Too many components. A huge catalogue makes selection harder and slower, just like giving a person 200 menu items. Start with a handful of high-value components and grow deliberately.
  • Forgetting it can still be wrong. Schema validation guarantees the shape of the props, not that the choice was correct. The agent can pick a sensible-but-wrong component or fill plausible-but-off values. Design for graceful recovery and let users correct it, as covered in AI error state design.
  • Ignoring latency. Choosing a component and streaming its props takes model time. Show a loading state so the UI feels responsive — see designing for LLM latency.

Going deeper

Once the basic register-then-pick loop clicks, a few deeper ideas are worth knowing.

Streaming props, not just final answers. Tambo streams the props as the model produces them, so a component can begin rendering before every field arrives. That keeps generative UI feeling fast, but it means your components should tolerate partial props gracefully — render a skeleton while a value is still on its way rather than assuming everything is present at first paint.

Interactable components and shared state. The line between "the AI showed me a thing" and "the AI and I are editing a thing together" is the interactable pattern. When a component persists and updates across turns, both the user's direct interactions and the agent's later prop updates have to converge on one source of truth. This is genuinely human-in-the-loop UX: the human and the model take turns mutating the same state, and you have to decide who wins on conflict.

Tools and MCP alongside components. Because Tambo already speaks the model's tool-calling language, the same agent can be given ordinary tools (call an API, run a query) and external data sources via the Model Context Protocol — then render the result as a component. The interesting systems blend the two: fetch data with a tool, then choose a component to present it.

Security still applies. A user message is untrusted input, and a generative-UI agent acts on it. Keep the boundary that makes schema-bound UI safe: the model selects from your catalogue and fills validated props — it should never be in a position to render arbitrary markup or trigger a privileged action without confirmation. Combine it with the trust patterns in what makes good AI UX, especially clear sourcing and reversible actions.

The durable lesson: generative UI moves the creative decision (which interface fits this request) to the model while keeping the deterministic parts (how each component looks and behaves) in your code. Tambo's bet is that a small, well-described, schema-bound catalogue is the safest place to draw that line. Whether or not you adopt this specific SDK, that division of labour is the idea worth taking with you.

FAQ

What is Tambo in AI?

Tambo is an open-source generative-UI SDK for React. You register a set of React components, each described by a Zod schema, and the agent decides which component to render and with what props — so the AI answers with interactive UI instead of plain text.

How does Tambo's generative UI actually work?

Each registered component's Zod schema becomes a tool definition the model can call. When a user sends a message, the agent picks the component that fits, generates props that match the schema, Tambo validates them, and your real React component renders live in the conversation.

Why does Tambo use Zod schemas?

The Zod schema does two jobs: it tells the model what props are valid so it can fill them correctly, and it validates the model's response before rendering. That keeps the agent choosing only from your approved, typed component set instead of generating arbitrary markup.

What is the difference between Tambo and CopilotKit?

Both are open-source and can render generative UI, but their scope differs. CopilotKit is a broad frontend stack for agent-native apps (chat surfaces, shared state, agent-to-UI wiring), while Tambo is narrowly focused on model-chosen, schema-bound React components. Pick Tambo if you specifically want the agent to choose from your typed component catalogue.

Is Tambo production-ready?

Tambo is active and emerging rather than an established default. It is a promising approach worth prototyping with, but treat schema-bound generative UI as a fast-moving pattern, design for the agent occasionally picking the wrong component, and validate everything with schemas.

What is the difference between generative and interactable components in Tambo?

Generative components render once as part of a single response, like a chart or summary card you read and move on from. Interactable components persist and update across turns, like a cart or task board the user keeps refining, letting a conversation drive a small app rather than emit one-shot widgets.

Further reading