Interactive Answers
Result Carousel
A row of result cards — image, title, meta and an action — with snap scrolling and arrows.
2 variantsMIT
Preview
Hotels in Lisbon
Nov 14–17 · 2 guests · under $260
Installation
Copies the component into components/ui and installs its dependencies and theme tokens.
pnpm dlx shadcn@latest add https://tuffui.com/r/result-carousel.jsonUsage
Pass your own data and wire the callbacks to your agent runtime.
import { ResultCarousel } from "@/components/ui/result-carousel";
// Render search results the agent found; the action hands the pick back to it.
export function HotelsAnswer({ results }: { results: Hotel[] }) {
return (
<ResultCarousel
title="Hotels in Lisbon"
subtitle="Nov 14–17 · 2 guests"
data={results.map((h) => ({
id: h.id,
title: h.name,
meta: h.area,
price: `$${h.rate} / night`,
rating: h.rating,
image: h.photoUrl,
action: "Book",
}))}
onAction={(item) => agent.send(`Book ${item.title}`)}
/>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| data* | ResultItem[] | — | Cards in order. New items can be appended while results stream in. |
| title* | string | — | Header title and the carousel's accessible name. |
| subtitle | string | — | Replaces the default result count. |
| compact | boolean | false | Narrower cards without the image area. |
| onAction | (item: ResultItem) => void | — | Adds a button to each card; the first card's button is primary. |
| onOpen | (item: ResultItem) => void | — | Makes the title and image open the item. |
| className | string | — | Extra classes for the root element. |
type ResultItem = {
id: string;
title: string;
meta?: string; // one line under the title
price?: string; // right-aligned, e.g. "$214 / night"
rating?: number; // 0–5
image?: string; // URL; without it a gradient from `tint`
tint?: string;
badge?: string; // e.g. "Best match"
action?: string; // button label, default "Select"
};
// The track scrolls with snap; arrows page by one card and disable at the ends.