Inspiration Cards

Visual ideas as image cards with a title and one line, with an optional pick.

Pattern

≈ 1,150 tokens per use (tool 577 · guidance 293 · typical payload 280)How token costs are estimated

Example: Inspiration Cards

Outfit ideas for a wedding trip to Italy

Your Italy outfit inspiration

  • Woman in a white tee, wide linen trousers and sandals, with a leather toteSightseeing chicLinen trousers, a simple top, comfortable sandals.
  • Woman in a terracotta midi dress with nude heels and a small clutchWedding guestA terracotta midi dress, block heels, a small clutch.
  • Woman in a champagne slip dress with gold earrings and strappy sandalsEvening aperitivoA champagne slip dress with strappy sandals.
  • Woman in a blue and white striped sundress and straw hat, holding a basket bagDay on the coastA striped sundress, a straw hat, espadrilles.

When to use

  • The user asks for visual ideas: outfits, interior styles, recipes, gift ideas, hairstyles, party themes.
  • Each idea has an image, a short name and at most one line of detail.
  • The user wants to pick the ideas they like before the agent goes further.

When not to use

  • The agent doesn't have real image URLs. It must never invent or guess them.
  • The items are records to compare by price, rating or specs. Use a Comparison Matrix or an Entity Card.
  • One scene-setting collage is enough. Use a Photo Mosaic.
  • The topic is fashion, with four or more looks the user may want to browse and save. Use a Style Board.

How the agent should use it

  • Take every image src and url from a tool result or the host, never from memory. Only http(s) URLs and data:image/(png|jpeg|webp|svg+xml) images load; a link that isn't http(s) is dropped.
  • Keep titles to a few words and the line under 90 characters. No marketing copy.
  • Use 2–8 cards. Set columns: 3 for six or more compact ideas; otherwise keep the default 2. Phones always show 2.
  • Write real alt text for each image. On cards that are buttons or links, the title names the card and the alt text describes it.
  • Set selectable only when the user is choosing, with a specific submitLabel and max when it matters. In selectable mode, url is ignored.
  • Lifecycle: ideas are a snapshot, so it usually needs none. When they come from a live catalog with prices, set fetchedAt (and staleAfterMs, e.g. a day). When the agent sends a new set, mark the old call superseded (supersededBy).

Interaction

  • Display-only (the default): a card with a safe url is a link that opens in a new tab and sends { action: "open", id } for analytics. Cards without one are static.
  • Selectable: each card is a toggle (aria-pressed) with a check badge on the image corner and a ring when picked. max is enforced: once it's reached, the other cards are disabled until one is removed. The footer shows the count ("2 of 3 selected"; with nothing picked, the instruction is read to screen readers only) and the submit button, disabled until something is picked. After submitting, the picked cards stay forward, the others dim, and the footer reads "Chose Soft arches and Low and grounded".
  • Broken images: an image that fails to load, or whose src isn't allowed, becomes a neutral tile showing its alt text.
  • Streaming: cards append as they arrive, with a placeholder card for the next one; actions are disabled until the call completes. Images load lazily.

Installation

npx shadcn@latest add https://your-site.com/r/inspiration-cards.json

Usage

app/api/chat/route.ts
import { tool } from "ai"
import { inspirationCardsTool } from "@/components/genui/inspiration-cards.schema"

const tools = {
  [inspirationCardsTool.name]: tool({
    description: inspirationCardsTool.description,
    inputSchema: inspirationCardsTool.inputSchema,
  }),
}

With selectable: "none" the cards are display-only, so give the tool an execute that returns immediately. With "single" or "multiple", the agent receives:

{ action: "select", ids: ["arches", "low"] } // in card order

Link opens send { action: "open", id: "cap" }. They are analytics only and never lock the cards; the agent doesn't need to answer them.

With LangGraph

Push it from a graph node with ui.push({ name: "show_inspiration", props: { toolCallId, ...args } }, { message }), and render the thread's UI messages with the Renderer.

Restoring from history

When a conversation is reloaded, pass the stored result back as result. A select result restores the pick (check badges, rings and the footer) read-only and never calls onResult again, so a choice can't be sent twice. With the AI SDK, that's the tool call's output:

<InspirationCards
  {...part.input}
  result={part.state === "output-available" ? part.output : undefined}
/>

Schema

PropTypeNotes
titlestring?e.g. "Your Italy outfit inspiration"
columns2 | 3Default 2. Phones always show 2
selectable"none" | "single" | "multiple"Default "none" (display-only)
maxnumber?Most picks with "multiple"
submitLabelstring?Submit button text. Default "Use these" ("Use this" for single)
itemsItem[]2–8 cards, below

An item is { id, image: { src, alt }, title, line?, url? }. image.src and url are data-bound; line is up to 90 characters.

Host props: status (streaming, ready, selected), onResult, result and className.

Source

On this page