Generative UI in React: turn tool results into useful views
Generative UI lets a model's response determine which interface appears, such as a search result, usage summary or approval request. A practical React pattern maps validated tool results to components your application already knows. The model selects a tool or view; your code controls the renderer, permissions and actions. affectUI supplies the presentation components for this pattern.
Choose a useful view for each result
- Research assistant: show an answer with the retrieved sources instead of a JSON dump.
- Usage assistant: show measured consumption against a limit supplied by your backend.
- Workflow assistant: show a proposed action for review before the server performs a write.
- Cited Answer – An AI answer wired to its sources – point at a citation to light up its sentence and source, click to unfold the quoted passage with the matching words marked
- Usage Meter – Plan usage and AI credits – a stacked credits meter by category, daily sparkline, limits and a button that speaks up near the limit
- Approval Card – An agent asks before it acts – risk badge, preview, Approve and Deny with shortcuts, a pausing countdown, and a smooth morph into a resolved row
Keep the renderer under application control
Define an allowlist of view types and a schema for each payload. Validate the type, required fields, size limits and any destination URLs before rendering. Unknown or incomplete data should produce a plain fallback. Do not evaluate model-generated JavaScript, dynamically import model-chosen modules or inject untrusted HTML.
- The backend authenticates the user and checks access to each tool and data source.
- Your adapter validates the result and turns it into component props.
- The React view presents those props. Button callbacks call your authorized application endpoints.
A small view switch with a fallback
This example accepts a tool summary after your adapter has validated it. The allowlist has one view type; unsupported types render a text fallback. Tool Call Card displays the summary and does not execute a tool.
import { ToolCallCard } from "@/components/ui/tool-call-card";
type View = { type: "tool-summary"; name: string; summary: string };
export function ResultView({ view }: { view: View | null }) {
if (!view || view.type !== "tool-summary") {
return <p>No supported result to display.</p>;
}
return (
<ToolCallCard
name={view.name}
summary={view.summary}
status="success"
/>
);
}- Tool Call Card – An agent's tool call in one line – live timer, status and summary, folds open to highlighted arguments and result with copy, retry on errors and a group that sums them up
Handle streaming and failure explicitly
Keep a stable message or result ID while data arrives. Show progress before a complete payload is available, validate the finished result, and replace the pending view with its content or an error. A timeout should leave a readable explanation and a safe recovery action. Keep a person's input when retrying.
- Thinking Loader – A small working pill for AI replies – an eight-ray spinner and a shimmering label that rolls through phases and settles on a check
- Message Actions – The quiet bar under an AI message – copy turns into a check, regenerate spins and unfolds a version switcher, thumbs pop and ask why, read aloud becomes a tiny equalizer
Questions
Does generative UI require generating React source at runtime?
No. Mapping model-selected tools and validated results to prebuilt React components is a generative UI pattern. It gives your application control over what runs and how results look.
Can I use affectUI with my existing AI backend?
Yes. Map your backend's validated data to component props and connect callbacks to your application. affectUI does not provide the model, tool execution, result validation or a runtime SDK for this flow.
Does a TypeScript type validate model output?
No. TypeScript types do not check incoming data at runtime. Validate unknown tool responses before passing them to a typed view, and keep authorization on the server.
Updated 2026-11-05