npx tool-agent "integrate the item carousel component for horizontal browsing of collections"npx shadcn@latest add @tool-ui/item-carouselA vertical list of ten search results buries everything below the fold. ItemCarousel lays them out in a scrollable row of cards so the user can browse products, restaurants, or any collection the assistant returns without losing their place in the conversation. Each card shows an image, subtitle, and action buttons.
Role: Information. For displaying data without user input. See Design Guidelines for how component roles work.
Run this once from your project root.
npx tool-agent "integrate the item carousel component for horizontal browsing of collections"npx shadcn@latest add @tool-ui/item-carouselRender ItemCarousel in your UI with tool-compatible props.
import { ItemCarousel } from "@/components/tool-ui/item-carousel";export function Example({ payload,}: { payload: React.ComponentProps<typeof ItemCarousel>;}) { return <ItemCarousel {...payload} />;}Registration tells assistant-ui which component to render when a tool named searchItems returns data. Without it, tool results appear as raw JSON.
// Backend toolimport { tool } from "ai";import { z } from "zod";import { SerializableItemCarouselSchema } from "@/components/tool-ui/item-carousel/schema";const searchItems = tool({ description: "Search for items matching criteria", inputSchema: z.object({ query: z.string(), maxPrice: z.number().optional(), }), outputSchema: SerializableItemCarouselSchema, async execute({ query, maxPrice }) { const items = await fetchItems(query, maxPrice); return { id: `item-search-${query}`, items: items.map((item) => ({ id: item.id, name: item.name, subtitle: `$${item.price.toFixed(2)}`, image: item.imageUrl, actions: [ { id: "view", label: "View Details" }, { id: "select", label: "Select", variant: "default" }, ], })), }; },});// Frontend with assistant-uiimport { type Toolkit } from "@assistant-ui/react";import { ItemCarousel } from "@/components/tool-ui/item-carousel";import { safeParseSerializableItemCarousel } from "@/components/tool-ui/item-carousel/schema";export const toolkit: Toolkit = { searchItems: { type: "backend", render: ({ result }) => { const parsed = safeParseSerializableItemCarousel(result); if (!parsed) { return null; } return ( <ItemCarousel {...parsed} onItemClick={(id) => router.push(`/items/${id}`)} onItemAction={(itemId, actionId) => { if (actionId === "select") { selectItem(itemId); } }} /> ); }, },};Equal-height cards via CSS Grid so items line up regardless of title length
Smooth scroll with snap points and reduced-motion fallback
Buttons stack or sit side-by-side based on card width via container queries
Enter/Space activation, focus rings, and ARIA roles throughout
Prop
Type
Prop
Type
prefers-reduced-motion and fall back to instant scrolling