<OptionList options={[ { "id": "good", "label": "Good", "description": "High quality work" }, { "id": "fast", "label": "Fast", "description": "Quick turnaround" }, { "id": "cheap", "label": "Cheap", "description": "Low cost" } ]} maxSelections={2} actions={[ { "id": "cancel", "label": "Reset" }, { "id": "confirm", "label": "Confirm", "variant": "default" } ]} onAction={(actionId, selection) => { if (actionId === "confirm") { console.log("Selection:", selection); } }}/>Not every choice fits in a text reply. When the assistant needs the user to pick an output format, a plan tier, or a movie genre, OptionList renders the options as selectable cards with single or multi-select behavior. The selection feeds back as a tool result, and the chosen option stays visible as a receipt. No free-text parsing required.
Role: Decision. For choices that return to the assistant. See Design Guidelines for how component roles work.
Run this once from your project root.
npx shadcn@latest add @tool-ui/option-listRender OptionList in your UI with tool-compatible props.
import { OptionList } from "@/components/tool-ui/option-list";export function Example({ payload,}: { payload: React.ComponentProps<typeof OptionList>;}) { return <OptionList {...payload} />;}Register this renderer so tool results display as OptionList.
"use client";// Frontend tool (recommended for decision surfaces like Option List):// - The model calls the tool with SerializableOptionList props as the args// - Your UI calls addResult(selection) from onAction when actionId is "confirm"import { type Toolkit } from "@assistant-ui/react";import { OptionList } from "@/components/tool-ui/option-list";import { safeParseSerializableOptionList, SerializableOptionListSchema,} from "@/components/tool-ui/option-list/schema";import { createArgsToolRenderer } from "@/components/tool-ui/shared";export const toolkit: Toolkit = { selectFormat: { description: "Let the user choose an output format.", parameters: SerializableOptionListSchema, render: createArgsToolRenderer({ safeParse: safeParseSerializableOptionList, idPrefix: "format-selection", render: (parsedArgs, { result, addResult }) => result ? ( <OptionList {...parsedArgs} value={undefined} choice={result} /> ) : ( <OptionList {...parsedArgs} // Avoid controlled selection in LLM-driven payloads. value={undefined} onAction={(actionId, selection) => { if (actionId === "confirm") { void addResult?.(selection); } }} /> ), }), },};Radio buttons for one choice, checkboxes for many
Set minimum and maximum selection counts
Confirm, cancel, and custom footer buttons
Shows only the chosen option(s) as a read-only record
Pass a choice prop to render this component in its receipt state. See Receipts for the pattern.
The receipt shows only the selected option(s) with a checkmark. Unselected options and action buttons are hidden.
Prop
Type
Prop
Type
role="listbox" with role="option" on each option button)aria-selected and multi-select intent with aria-multiselectableArrowUp/ArrowDown, Home/End, Enter/Space, Escape)