Question

A multiple-choice question from the agent. Pick with number or arrow keys, or type your own answer.

Loading preview…

Install

  1. 1

    Run this command in your Tailwind CSS project. It adds components/ai/question-default.tsx and installs its dependencies.

    $ npx shadcn@latest add https://gradientdeck.com/ai-components/r/question-default.json

Usage & API

Example

question-default.tsx
import { Question } from "@/components/ai/question-default"

<Question
  question="…"
  options={[]}
  onSubmit={() => {}}
/>

Props Question

PropType & descriptionRequired
questionstringRequired
optionsQuestionOption[]Required
allowOtherbooleanAdds an "Other" choice with a text field.Optional
onSubmit(answer: string) => voidRequired
onSkip() => voidShows a "Skip" button that hands the composer back without answering.Optional

Dependencies

  • React
  • Tailwind CSS
  • motion
  • lucide-react
Implementation notes

The box is a radiogroup labeled by the question. Each option is a radio button showing an index, the label, and hint if you passed one. The selected row is highlighted. Keys 1 through 9 select a row when focus is not in the text field, and only if that index exists. Arrow keys move the selection. Arrow up is ignored while the other field is focused. Enter submits. Escape calls onSkip, and only if you passed it. The footer note reads that the number keys pick, and mentions Esc when skip exists. Something else is included unless allowOther is false. Submitting calls onSubmit with the label string, or with the trimmed custom text. Skip calls onSkip and does not call onSubmit.

Choosing a layout

Use a question when the agent is blocked on a preference: where to keep a queue, whether existing sessions stay valid, which of two designs to follow. The options should be answers the agent can act on. hint, on the composer form, is the short consequence under a label. description, on the decision list, is the longer one. Prefer the composer form when it should replace the input until the person answers, including the case where they need to type something you did not list. Pass onSkip only when skipping is a real outcome and your code will resume without an answer.

Prefer the decision list when the choice should remain in the thread as a fieldset, with a description on every row, and you do not want a free-text path. Tool approval is the wrong control when nothing is about to be executed. Approval is deny, once or always on a command. A plan is the wrong control when the person is not accepting a sequence of work. After onSubmit, replace the question with the reply that uses the answer. The composer form does not draw a resolved state of its own. The decision list does not either, aside from the selected radio while it is still mounted.

What does onSubmit receive?

On the composer question, the selected option's label, or the trimmed contents of Your answer when Something else is selected. The option id is not included. On the decision list, onSubmit receives the choice id and not the title. If you need the title later, look it up from the id you were given.

How do I let someone decline to answer?

Pass onSkip to the composer question. That shows Skip, and Escape calls it. Leave onSkip unset and there is no Skip button and Escape does nothing. The decision list cannot skip. It submits only a selected id. allowOther false removes Something else, which is a different thing: the person must still pick one of your options.