Skip to content

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

Casa do Rio

Alfama · 0.6 km from center

4.8out of 5$214 / night

Miradouro Suites

Graça · city view terrace

4.6out of 5$188 / night

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

Usage

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

PropTypeDefaultDescription
data*ResultItem[]—Cards in order. New items can be appended while results stream in.
title*string—Header title and the carousel's accessible name.
subtitlestring—Replaces the default result count.
compactbooleanfalseNarrower 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.
classNamestring—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.