We’re adding an AI assistant to our SaaS product and I’m trying to figure out the best approach for the chat interface. The assistant calls backend tools (database lookups, API calls, file operations) and we want to show users what’s happening in real time, not just the final text response.
The basic streaming text part is straightforward with the Vercel AI SDK’s useChat hook. But the tool-use visualization is where it gets tricky. When the model decides to call a tool, we want to show:
- A collapsible “thinking” step that shows which tool is being called and why
- A loading state while the tool executes
- The tool result rendered inline (sometimes it’s a table, sometimes a code block, sometimes a chart)
- The model’s follow-up response that references the tool output
I’ve been looking at a few approaches:
AI Elements (shadcn-based)
This library popped up recently with 20+ React components built specifically for AI chat interfaces. Message threads, reasoning panels, tool-call cards, the works. It’s built on shadcn/ui so it should integrate with our existing design system. But it’s new and I’m not sure how battle-tested it is. Has anyone shipped with it?
Roll our own with shadcn primitives
We already use shadcn/ui heavily. I could build the chat components from scratch using their Card, Collapsible, and ScrollArea primitives. More control, but a lot of work to get the streaming UX right (auto-scroll behavior, partial render during stream, handling tool calls mid-stream).
CopilotKit
Seems more opinionated and full-featured. Built-in tool rendering, generative UI support, works with multiple LLM providers. But I’m worried about lock-in and how much flexibility we’d have to customize the look and feel.
Some specific questions:
-
Streaming + tool calls: When a model response includes a tool call in the middle of generating text, how do you handle the rendering transition? The Vercel AI SDK gives you
toolInvocationsin the message object but the timing of when to show the tool card vs the surrounding text is finicky. Any patterns that work well? -
Optimistic tool UI: Do you show the tool-call card immediately when the model requests it, or wait until the tool actually returns? We tried optimistic rendering but it felt weird when a tool call failed and we had to remove the card.
-
Accessibility: Screen readers and streaming text don’t play well together. We need this to be WCAG 2.1 AA compliant. How are people handling live regions for streaming responses without overwhelming screen reader users with constant updates?
-
Mobile performance: We’re targeting mobile web too. The combination of streaming text rendering, tool-call animations, and inline data visualizations is a lot of DOM updates. Anyone profiled this kind of UI on mid-range Android devices?
Our stack is Next.js 15, React 19, shadcn/ui, Tailwind, and we’re calling the Claude API via our backend. Would love to see how others have structured their chat components.
Seed content posted by the DevForums team to help get our community started. Have a better answer? Jump in!