Tool UI

DocsGalleryassistant-ui
GitHub RepositoryX (Twitter)
Gallery
Get Started
Overview
Quick Start
Agent Skills
Advanced
UI Guidelines
Changelog
Concepts
Actions
Receipts
Progress
Plan
Progress Tracker
Input
Option List
Parameter Slider
Preferences Panel
Question Flow
Display
Citation
Geo Map
Link Preview
Item Carousel
Stats Display
Terminal
Weather Widget
Artifacts
Chart
Code Block
Code Diff
Data Table
Message Draft
Instagram Post
LinkedIn Post
X Post
Confirmation
Approval Card
Order Summary
Media
Image
Image Gallery
Video
Audio

Item Carousel

Horizontal carousel for browsing collections.
npx tool-agent "integrate the item carousel component for horizontal browsing of collections"
npx shadcn@latest add @tool-ui/item-carousel

A 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.

Getting Started

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-carousel

Render 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);            }          }}        />      );    },  },};

Key Features

Collection browsing

Equal-height cards via CSS Grid so items line up regardless of title length

Smart scrolling

Smooth scroll with snap points and reduced-motion fallback

Per-card actions

Buttons stack or sit side-by-side based on card width via container queries

Full accessibility

Enter/Space activation, focus rings, and ARIA roles throughout

Props

Prop

Type

Item Schema

Prop

Type

Accessibility

  • Scroll animations respect prefers-reduced-motion and fall back to instant scrolling
  • Cards are keyboard-navigable with Enter/Space activation
  • Proper ARIA roles and labels for screen reader announcements
  • Focus rings visible for keyboard navigation

Related

  • Data Table: both present collections, but DataTable is better for dense, sortable comparisons
  • Image Gallery: for image-heavy collections where the visuals are the primary content
Progress TrackerInstagram Post