assistant-ui/tool-ui: React Components That Turn Tool Call Payloads Into Chat UI
UI components for AI interfaces
At a glance
- What is it?
- Tool UI is a copy/paste component collection for rendering model tool calls as approvals, forms, tables and charts inside a chat thread. It is a good fit if you already run shadcn/ui and can enforce Zod validation at the tool boundary; it is the wrong tool if you want a single npm package that owns the rendering lifecycle.
- Who is it for?
- Adopt Tool UI if your chat client already uses shadcn/ui, Tailwind and Zod, and you are willing to vendor roughly thirty components into your own repository and keep them updated by hand. Do not adopt it if you need a versioned package with a stable public API, or if your tool call payloads are not schema-stable.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 16 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem Tool UI targets: raw JSON in the chat transcript
The README states the case directly: when a model calls a tool, most apps dump raw JSON into the conversation. That is accurate for a large class of agent front ends. The model returns a tool result, the client stringifies it, and the user sees a wall of braces. If the tool was supposed to collect a decision, the user has to read the payload, work out what the options are, and type a reply that the model then has to parse back.
Tool UI addresses the rendering half of that problem. Its components convert tool payloads into approvals, forms, tables, charts and media cards, per the README's own summary. The audience is narrow and specific: React developers building chat interfaces who already have a tool calling loop and now need the output side of it. It is not a model client, not an agent framework, and not a state manager. The repository description is simply "UI components for AI interfaces," and the component list bears that out.
The second half of the problem is the return path. The README describes components as interactive with receipts: users make choices that flow back to the assistant, and those choices persist as receipts. That is the part most chat UIs skip. A rendered form that cannot send its result back is just a nicer error message.
How the schema-validated rendering flow works
Each component ships with a Zod schema. The README's stated pattern is: parse tool output, render when valid, fail safely when not. That is the whole mechanism, and it is worth being precise about what it implies. The model's tool result is untrusted input. You run it through the component's schema, and only on a successful parse do you mount the component. On failure you fall back to whatever you render for unparseable output.
This is a different architecture from a component library that accepts a loosely typed props object. The schema is the contract between your tool definition and the UI. If your tool returns `{ options: [...] }` and the Option List schema expects a different key, the component will not render. That coupling is the point: it forces the tool's output shape and the UI's input shape to be the same thing, and it moves failures to a place you can log rather than a place the user sees as a blank card.
The README also mentions presets for realistic example data. Those are useful for building the component in isolation before wiring a live model, since you can render the preset payload without a tool call. The repository is TypeScript, so the schemas carry inferred types, though the README does not document a generated type export convention.
The interactive components close the loop. Option List, Parameter Slider, Preferences Panel and Question Flow collect input; Approval Card and Order Summary collect a decision. The README says choices persist as receipts, which means the selection is retained rather than discarded after the model's next turn. How that receipt is stored and replayed is not described in the README, and I cannot confirm it from the supplied material.
Installation is copy/paste, and that is a real architectural decision
The README is explicit: copy/paste, not install, following the shadcn/ui model, with components living in your codebase and no dependency lock-in. There is no npm package to add to `dependencies`. You copy source files in.
The practical consequences run in both directions. On the positive side, you can edit any component without forking, patch a schema to match your payload naming, and you never hit a breaking change from a minor version bump, because there are no version bumps. On the negative side, upstream fixes do not reach you. If a chart component has a rendering bug and it is fixed on `main`, you will not know unless you are watching the repository, and you will not receive it unless you diff the file yourself. The README does not describe an update command analogous to `shadcn diff`, and no releases were retrieved for this repository, so there is no changelog to scan either.
The styling layer is stated as Radix primitives and Tailwind, using your theme, with no new design system to learn. That is a hard prerequisite rather than a preference. If your chat client does not already run Tailwind and shadcn/ui, the pasted components will not style correctly and you will be reconciling two token systems before you render a single approval card.
The README points to a Quick Start page at tool-ui.com/docs/quick-start for setup, and to a Gallery for browsing components. It does not inline the scaffold command, the directory convention for pasted files, or the required Tailwind config keys. I have not installed or run this project, so I cannot state those from experience. Check the Quick Start page for the exact command before you plan the work.
Where the component set is thin, and where it is not
The component list is organised into six groups, and the distribution is informative. Confirmation has two entries: Approval Card and Order Summary. Media has three: Audio, Image, Image Gallery, plus Video. Progress has two. Input has four. Display has eight. Artifacts has eight.
Artifacts and Display are where the depth is: Chart, Code Block, Code Diff, Data Table, Instagram Post, LinkedIn Post, Message Draft, X Post, plus Citation, Geo Map, Item Carousel, Link Preview, Stats Display, Terminal and Weather Widget. Several of these are narrow. Instagram Post, LinkedIn Post and X Post are social preview renderers; Weather Widget is a single-purpose display. If your product is a coding agent, Code Diff and Terminal are the ones that matter. If it is a research assistant, Citation and Link Preview are the ones that matter. The breadth looks like a gallery built for demonstration as much as for production coverage.
The confirmation group is the thinnest, and it is arguably the most valuable category in an agent product, because approvals are where a wrong render has consequences. Two components is a starting point, not a complete approval vocabulary. Expect to write your own for anything beyond a straightforward accept/reject or an order summary.
One thing the README does not address is accessibility. Radix primitives carry a baseline, but a multi-step Question Flow with branching is exactly the kind of component where keyboard traversal and focus management need deliberate work. There is no accessibility statement in the supplied material.
The limitation that matters: schema drift between your tools and the components
The schema validation is presented as a safety feature, and it is, but it cuts the other way too. The component schemas are fixed. Your tool definitions are not. Every time you change a tool's output shape, you either update the corresponding component schema or the component silently stops rendering and falls back to your failure path.
In a small app with three tools, that is manageable. In an agent with twenty tools whose payloads evolve weekly, the schemas become a maintenance surface that sits between the model and the UI, and nobody owns it by default. The failure mode is quiet: the user sees the fallback, not an error, and you find out from a support ticket rather than a stack trace.
There is a second, sharper case where Tool UI is the wrong tool. If your tool outputs are not schema-stable, meaning the model is allowed to return freeform text or a shape that varies by prompt, there is nothing for the Zod schemas to validate against and the components will mostly fail to parse. Tool UI assumes you control the tool contract. If you are working with MCP servers you do not own, whose output shapes you cannot pin, the copy/paste model does not help you, because the schemas you would need to edit are the ones describing someone else's server.
The repository lists `mcp` as a topic, which suggests the maintainers see MCP as a target use case. That is plausible for servers with stable output contracts, but the README does not describe an MCP-specific adapter or a schema negotiation step, and I cannot confirm one exists.
How this differs from using an all-in-one chat component library
The obvious alternative is a chat UI library that ships tool call rendering as part of a larger package, where the message list, composer, streaming state and tool rendering all come from one dependency and one version number. The difference is not cosmetic.
With a packaged library, the rendering of a tool call is the library's responsibility. You pass a payload, the library decides how to display it, and you get fixes through a version bump. You also get whatever visual treatment the library chose, and you get its release cadence whether or not it suits you.
Tool UI inverts that. You own the component source, so you own the visual treatment, the schema, and the bugs. The trade is control for maintenance. There is no upgrade path in the README and no releases were retrieved, so the maintenance burden is entirely on the adopter: watch the repository, diff the files you copied, re-apply your local edits.
A second alternative is to write the components yourself. For one or two payload types, that is genuinely reasonable, and the README's own framing supports it: the value here is a starting set of schemas and layouts, not a framework. If you only need an approval card, you may spend less time writing it than reading the docs, copying files, and reconciling dependencies. Tool UI pays off when you need many payload types and want consistent conventions across them.
The shadcn/ui lineage is worth noting as a third comparison point. Anyone who has used shadcn/ui already understands the model and its costs. Tool UI is that model applied to tool call rendering, and it inherits both the flexibility and the update problem.
Maintenance cost, licensing and what to check first
The licence is MIT, stated in the README with a pointer to LICENSE.md. That is permissive and places few obligations on how you use the components, but I am not a lawyer and this is not legal advice. If you are vendoring source into a commercial product, read LICENSE.md and your own policy rather than relying on the README summary.
The maintenance picture is the part to weigh honestly. There are no releases retrieved for this repository, which means the distribution channel is the repository itself rather than a package registry. Updates arrive as commits. Your cost is the time to notice them and the time to merge them into files you have already modified. For a team that has customised several components, that merge is manual and repeated.
The dependency cost is Tailwind, shadcn/ui and Radix. If those are already in your stack, the marginal cost is low. If they are not, the cost is not the components, it is adopting the styling stack first.
What to verify before committing: the Quick Start page for the actual scaffold command and file layout, since the README does not inline it. The Zod schema for the single component you need most, to confirm its field names match what your tools already emit. Whether the receipt mechanism for interactive components is documented anywhere beyond the README's one-line mention, because if your product depends on persisting user choices, that is the piece you cannot afford to discover late.
Editorial conclusion
Adopt Tool UI if your chat client already uses shadcn/ui, Tailwind and Zod, and you are willing to vendor roughly thirty components into your own repository and keep them updated by hand. Do not adopt it if you need a versioned package with a stable public API, or if your tool call payloads are not schema-stable. Before writing code, open the Quick Start page and confirm the exact scaffold command, check the Zod schema for the one component you actually need (Approval Card or Option List are the smallest useful starting points), and verify that your tool definitions emit payloads whose field names match those schemas rather than your own naming.
Community notes