Follow-up Chips

One-tap next steps the agent offers after an answer.

Pattern

≈ 543 tokens per use (tool 289 · guidance 212 · typical payload 42)How token costs are estimated

Example: Follow-up Chips

Give me a plan for a Sunday lamb roast. I'm still figuring out numbers.

When to use

  • You finished an answer or a task, and there are 2–4 likely, specific next steps.
  • The user may not know about a useful thing you can do next, like adjusting a plan or exporting results.

When not to use

  • The user already said what they want next.
  • The only suggestions you have are filler, like "Tell me more" or "Anything else?".
  • You need an answer before you can continue. Use a Question Stepper.
  • A task is waiting for approval. Finish that first.

Writing suggestions

DoDon't
Adjust the plan for 5 guestsWould you like me to adjust the plan?
Copy these changes to Google AdsMore options
Does it work with oat milk?Tell me more

Write each label as the user's own request, under 60 characters, and only offer what you can actually do. Use prompt when the message you need is longer than the label.

Layouts

  • chips (default) for short actions.
  • list for longer, question-like suggestions, like a "Related" section.

Suggestions can be tapped as soon as they stream in. After a tap, the chosen one stays marked and the others dim, so the chat history shows what was picked.

Installation

npx shadcn@latest add https://your-site.com/r/follow-up-chips.json

Usage

app/api/chat/route.ts
import { tool } from "ai"
import { followUpChipsTool } from "@/components/genui/follow-up-chips.schema"

const tools = {
  // No execute(): the call is completed by the user's tap in the UI.
  [followUpChipsTool.name]: tool({
    description: followUpChipsTool.description,
    inputSchema: followUpChipsTool.inputSchema,
  }),
}
components/message.tsx
import { FollowUpChips } from "@/components/genui/follow-up-chips"

function ToolPart({ part, addToolResult }) {
  if (part.type !== "tool-suggest_follow_ups") return null

  return (
    <FollowUpChips
      {...part.input}
      status={part.state === "input-streaming" ? "streaming" : undefined}
      result={part.state === "output-available" ? part.output : undefined}
      onResult={(result) =>
        addToolResult({
          tool: "suggest_follow_ups",
          toolCallId: part.toolCallId,
          output: result,
        })
      }
    />
  )
}

The agent receives:

{ action: "select", id: "guests", prompt: "Adjust the plan for 5 guests" }

Treat prompt exactly as if the user had typed it. Many apps also send it as a visible user message, which is what the user expects to see.

With LangGraph

Push it from a graph node with ui.push({ name: "suggest_follow_ups", 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. The component renders its finished state (the chosen suggestion) and never calls onResult again, so a decision can't be made twice. With the AI SDK, that's the tool call's output:

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

Schema

PropTypeNotes
labelstring?A short group label such as "Related". Leave it out when the chips speak for themselves
suggestions{ id, label, prompt? }[]1–4. label is at most 80 characters
layout"chips" | "list"Default chips

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

Source

On this page