Interactive

OptionList

Let the AI propose choices and the human decide. Single or multi-select with keyboard navigation, AI reasoning, selection constraints, and the receipt pattern for post-decision display.

State

How should we deploy the database migration?

The migration includes 3 schema changes and 1 data backfill.

Installation

Terminal
npx taw-ui add option-list

This copies the component source and schema into your project. You own the code — customize anything.

Usage

server — define tool
import { tool } from "ai"
import { OptionListSchema } from "@/components/taw/option-list"

export const chooseAction = tool({
  description: "Present options for user decision",
  parameters: z.object({ context: z.string() }),
  outputSchema: OptionListSchema,
  execute: async ({ context }) => {
    const options = await generateOptions(context)
    return {
      id: "deploy-strategy",
      question: "How should we proceed?",
      options: options.map(o => ({
        id: o.id,
        label: o.label,
        description: o.detail,
        recommended: o.score > 0.8,
      })),
      reasoning: "Based on your infrastructure...",
      confirmLabel: "Confirm",
    }
  },
})
client — render
import { OptionList } from "@/components/taw/option-list"
import { createReceipt } from "taw-ui"

function ToolOutput({ part }) {
  const [receipt, setReceipt] = useState()

  const handleAction = (id, payload) => {
    if (payload.receipt) setReceipt(payload.receipt)
  }

  return (
    <OptionList
      part={part}
      onAction={handleAction}
      receipt={receipt}
    />
  )
}

Try It

Select an option and click Deploy. The list collapses to a receipt.

How should we deploy the database migration?

The migration includes 3 schema changes and 1 data backfill.

Infrastructure API· live

Props

FieldTypeDescription
part*TawToolPartTool call lifecycle state
onAction(id, payload) => voidCallback for confirm/cancel actions
receiptTawReceiptRenders the receipt state when provided
pendingbooleanDisables all interactions while processing
animatebooleanEnable entrance animations (default: true)
classNamestringAdditional CSS classes on the wrapper

Schema

Cross-field validation catches duplicate option IDs and invalid minSelections / maxSelections at parse time.

OptionListSchema
FieldTypeDescription
id*stringStable backend identifier
question*stringThe question or prompt shown to the user
descriptionstringAdditional context below the question
options*Option[]1-10 options to choose from
selectionMode"single" | "multi"Selection behavior (default: "single")
minSelectionsnumberMinimum selections required (default: 1)
maxSelectionsnumberMaximum selections allowed
requiredbooleanWhether cancel is hidden (default: true)
reasoningstringAI explanation for these options
confirmLabelstringConfirm button text (default: "Confirm")
cancelLabelstringCancel button text (default: "Skip")
caveatstringAI caveat or disclaimer
sourceSourceData provenance (label + freshness)
Option
FieldTypeDescription
id*stringUnique identifier within the list
label*stringDisplay label
descriptionstringDetail text below the label
badgestringCustom badge text (e.g. "Recommended")
recommendedbooleanPre-selects and shows green badge if no custom badge
disabledbooleanPrevents selection of this option
metaRecord<string, unknown>Arbitrary metadata passed through to receipts

Features

Single or multi-select

Radio buttons for single, checkboxes for multi — controlled by selectionMode

Selection constraints

minSelections and maxSelections enforce valid choices, auto-disabling when max is reached

AI reasoning

Optional reasoning panel explains why these options were presented

Receipt pattern

Collapses to a compact card showing selected options after decision

Pre-selects recommended

Options marked recommended are selected by default

Cross-field validation

Duplicate IDs and invalid min/max caught at parse time via .superRefine()

Accessibility

OptionList uses role="listbox" with role="option" on each item, aria-selected, and aria-multiselectable for multi-select mode. Navigation uses roving tabindex so only the focused option is in the tab order.

KeyAction
Arrow DownMove focus to next enabled option
Arrow UpMove focus to previous enabled option
HomeMove focus to first enabled option
EndMove focus to last enabled option
Enter / SpaceToggle selection on focused option

Related