"Chatbots that reply with Markdown are so 2023. The future is Generative UI."
Why return markdown text when you can return interactive React Components?
The Vercel AI SDK allows the LLM to call functions that return Server Components, which are then streamed to the client via a readable stream.
We call this Generative UI. The AI doesn't just talk; it paints the screen.
02. Generative UI
Standard AI: User asks "Stock price of AAPL". AI replies "It is $150".
Generative UI: User asks "Stock price of AAPL". AI replies with a stream that hydrates into a <StockChart ticker="AAPL" /> component.
💬 Text Stream
"Sure, I can help with that. Here is the data..."
⚛️ Component Stream
<Suspense><FlightCard /></Suspense>
03. Tool Calling (The Magic)
The secret sauce is Tool Calling. You define tools (functions) that the AI can "call". Next.js intercepts these calls on the server and renders the corresponding component.
// Server Action (actions.tsx)
export async function submitUserMessage(input: string) {
const ui = await render({
model: 'gpt-4-turbo',
messages: [{ role: 'user', content: input }],
tools: {
get_weather: {
description: 'Get the weather',
parameters: z.object({ location: z.string() }),
render: async function* ({ location }) {
yield <Spinner /> // 1. Show loading state
const weather = await fetchWeather(location)
return <WeatherCard data={weather} /> // 2. Stream final UI
}
}
}
})
return { ui }
}
04. Structured Outputs (JSON)
Sometimes you don't need UI; you need data. The SDK ensures strict JSON output using Zod schemas. No more "I'm sorry but as an AI..." prefixes ruining your `JSON.parse()`.
model: openai('gpt-4-json'),
schema: z.object({
recipe: z.object({
name: z.string(),
ingredients: z.array(z.string())
})
}),
prompt: 'Generate a lasagna recipe'
})
// Result is fully typed:
console.log(object.recipe.name); // 'Classic Lasagna'
06. AI Chat Simulator
Type "Show me AAPL stock" to see the AI generate a UI component instead of text.
Concept Component Streaming
The simulator below mocks the server response delay. Notice the "IsTyping" indicator vs the final UI render.