Controlled Generative UI
By the Syncfusion DevTutorials team · Last updated
Stop the agent writing walls of text. Let it pick from your own typed components, such as an order card or a refund form, and fall back safely when it asks wrongly.
What Generative UI Is
Generative UI = parts of the interface that the agent picks, fills or describes while it runs, instead of everything being fixed in advance.
In this lesson, you will let the agent show an order card, a refund form and a tracking timeline, using components your team built. You will also make sure a bad request can never break the screen.
So far, the agent has only written text. But some answers are not text. An order has a status and a delivery date. Tracking has steps. A refund has an amount.
Written as text, they become a wall of markdown.
Press Play, or use Next to go one step at a time.
- Frame 1: the same order data. On the left, a markdown table. On the right, your own OrderCard.
- Frame 2: tracking as one long paragraph, or as a timeline.
- The checks: the right component renders with typed props.
Simple lesson: when the answer has a shape, show it in a component, not a paragraph.
A Real-World Example
Think about a restaurant kitchen.
- The chef can only cook dishes that are on the menu.
- A waiter takes the order: "the fish, no sauce". That is the dish, plus a few choices.
- If a customer asks for a dish that is not on the menu, the waiter says so. The kitchen does not try to invent it.
Controlled generative UI works the same way:
- The menu = your component registry.
- The order = the agent's tool call: a component name and its props.
- "That is not on the menu" = a safe fallback.
Click the button. The Build tab shows the order through the naive interface.
- The screen: the agent's data as a markdown table.
- Events from the agent: a
tool-uievent naming OrderCard, with props. - The other scenarios: bad values and a component that does not exist.
Simple lesson: the agent already knows which component it wants. The app just needs a registry to draw it.
What You Will Learn
In this lesson, you will learn:
- The three kinds of generative UI, from safest to riskiest.
- How a typed component registry works.
- How to validate the props the agent sends.
- How to fall back safely when the agent asks wrongly.
About this section of the course
- Lessons 7 to 12 use the same Build tab as Section 1, with new settings for each lesson.
- Your Section 1 choices stay on, so streaming, sources and confirmations still work while you add generative UI.
- The renderer in the lab follows written-out rules, so the checks are exact. Real React apps follow the same rules.
The Generative UI Spectrum
Who decides what the UI looks like? There are three answers.
Step through all three frames.
- Frame 1: controlled. You built the components. The agent picks one and fills its props. Lowest risk. This lesson.
- Frame 2: declarative. The agent describes a layout in JSON, from a catalogue of parts you allow. Lesson 8.
- Frame 3: open-ended. A partner's server sends full HTML. It must run in a sandbox. Lesson 9.
| Pattern | Who decides the UI | Example | Risk |
|---|---|---|---|
| Controlled | You build it; the agent picks it | show_order_card | Lowest |
| Declarative | The agent arranges your parts | A refund form as JSON | Medium |
| Open-ended | Someone else sends the UI | A courier's MCP App | Highest |
Simple lesson: more flexibility for the agent means more risk for you.
The Component Registry
Component registry = a list that maps a name the agent can say to a component your app owns, with the type of every prop.
const REGISTRY = {
OrderCard: { component: OrderCard, props: { orderId: "string", status: "string", eta: "string" } },
RefundForm: { component: RefundForm, props: { orderId: "string", amount: "money", reason: "string" } },
TrackingTimeline: { component: TrackingTimeline, props: { orderId: "string", events: "list" } },
};
The agent gets one tool per component, such as show_order_card. When it calls the tool, your app looks up the name and renders your component with the props.
The agent never writes HTML. It only chooses from your list.
Simple lesson: the agent picks; your app renders.
When the Agent Asks Wrongly
The agent is a language model. Sometimes it fills a prop with nonsense, or asks for a component you do not have.
Step through both frames.
- Frame 1: the agent writes "lots" for the refund amount. Without a prop check, the form shows it.
- Frame 2: the agent asks for a MapView. Without a fallback, the panel crashes.
Validate Every Prop
Check each prop against its type before you render:
function renderToolUi(name: string, props: Record<string, unknown>, fallbackText: string) {
const entry = REGISTRY[name];
const error = entry ? validate(props, entry.props) : `no component ${name}`;
if (error) return <p>I couldn't show that as a card. {fallbackText}</p>;
const C = entry.component;
return <C {...props} />;
}
If any prop is missing, has the wrong type, or is not in the list, reject the whole request.
Never trust the props.
- A wrong amount on a refund form is a real risk.
- Validate types, not just presence: "lots" is not an amount.
- Reject unknown props too. They are how bad data sneaks in.
Fall Back Safely
A rejected request should never crash the panel. Show the answer as plain text instead, and log the problem for your team.
Easy way to remember: Known? Valid? Then render. Otherwise, text.
Simple lesson: validate every prop, and fall back to text when anything is wrong.
Lab Exercise: Build a Component Registry
Your task: change the Lesson 7 settings in the Build tab so all four scenarios pass. Then press Check all scenarios.
Click the button and open the Build tab.
- Typed component registry: lets the agent's tool calls render your components.
- Validate props: rejects the "lots" refund.
- When a request is rejected: pick the safe text fallback.
Simple lesson: a registry, a prop check and a fallback make generative UI safe to start with.
What Changes per Framework
| Option | Controlled generative UI |
|---|---|
| Hand-built React | A registry and renderToolUi, as above |
| CopilotKit | Render your own components for the agent's tool calls |
| Vercel AI SDK UI | Render tool parts of a message with your own components |
| Syncfusion AI components | Use Syncfusion components (for example a Grid or Card) as registry entries (optional, not graded) |
Build It in React
In the Code tab, the agent sends a tool-ui event with a component name and props. Look the name up in your registry. Check every prop before you render. If anything is wrong, show safe text instead.
const entry = REGISTRY[call.component];
const error = entry ? validate(call.props, entry.props) : "unknown component";
if (error) return <p>Here are the details as text.</p>;
Never pass props you did not check straight into a component.
TL;DR
- Generative UI = the agent picks, fills or describes parts of the UI at run time.
- The spectrum = controlled (lowest risk), declarative, open-ended (highest).
- Component registry = names the agent can say, mapped to your components and their prop types.
- Validate props = types, not just presence. Reject unknown props.
- Safe fallback = show text and log, never crash.
Common mistakes
| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
| Letting the agent write HTML | "It can make any UI." | Let it pick from your components. | You lose control of what the user sees. |
| Trusting the props | "The model knows the types." | Validate each prop. | A refund form shows "lots". |
| Crashing on unknown names | "It will only ask for real ones." | Fall back to text. | The whole panel goes blank. |
| One giant component | "One card for everything." | Small components with clear props. | The agent fills it wrongly more often. |
| No log of rejections | "The fallback handles it." | Log what was rejected. | You never learn which tool descriptions confuse the agent. |
Check Your Understanding
Exercises
What to Remember
- When the answer has a shape, show a component, not a paragraph.
- Controlled generative UI: the agent picks; your app renders.
- A registry maps names to components and prop types.
- Validate every prop. Reject unknown props.
- Fall back to text, never crash.
Further Reading
- The Developer's Guide to Generative UI in 2026, by CopilotKit: the three patterns, with examples.
- What is Generative UI?, by Google Cloud: control versus flexibility.
Next: Declarative UI with A2UI, where the agent describes a whole form in JSON and your renderer decides what is safe to draw.