Ask Question

Cursor-style questionnaire the agent can drop into a turn: single-select radios, multi-select checkboxes, an Other… field, Skip, and Continue.

Open in
What would you like to test next?
Which areas should we focus on?

Installation

npx shadcn@latest add miskibin/chat-components/ask-question

Also installs collapsible.

Usage

"use client"

import { AskQuestion } from "@/components/ui/ask-question"

export function Clarify() {
  return (
    <AskQuestion
      title="A couple of questions"
      questions={[
        {
          id: "next",
          prompt: "What would you like to test next?",
          options: [
            { id: "options", label: "Different options (Recommended)" },
            { id: "one", label: "One question only" },
          ],
        },
      ]}
      onSubmit={(result) => {
        if (result.skipped) return
        save(result.answers)
      }}
    />
  )
}

Examples

Restyle the selected option

Selected options carry data-state="checked", and the card, the submit button, and every fieldset have their own slots — so the questionnaire wears your accent without a fork. hideOther drops the free-text field, skipLabel and submitLabel rename the buttons.

Where should the fix land?

Render it from a tool call

MessageToolCall swaps in this card whenever isOpenAskTool holds: the tool name is Ask Question and it is either still running or already closed by the agent with nothing selected. After the user hits Skip or Continue it becomes the usual “Done Ask Question” row.

What would you like to test next?
Which areas should we focus on?

Skipped — nothing was selected.

title
A couple of questions
questions
[{"id":"next","prompt":"What would you like to test next?","options":[{"id":"options","label":"Different options (Recommended)"},{"id":"one","label":"One question only"},{"id":"pr…

Notes

API reference

AskQuestion

questions*AskQuestionItem[]
Each item is { id, prompt, options: [{ id, label }], allowMultiple? }. Append (Recommended) to a label to badge it. Other… is added automatically unless hideOther.
titlestring
Header label. Defaults to "Questions".
valueRecord<string, AskQuestionSelection>
Controlled selections keyed by question id.
defaultValueRecord<string, AskQuestionSelection>
Initial selections when uncontrolled.
onChange(value: Record<string, AskQuestionSelection>) => void
Fired on every option or Other… edit.
onSubmit(result: AskQuestionResult) => void
Continue. If onSkip is omitted, Skip also fires this with skipped: true.
onSkip() => void
Skip. Continue stays disabled until every question has a selection.
hideOtherboolean = false
Do not append the Other… option.
disabledboolean = false
Locks the form after a parent has recorded the answer.
defaultOpenboolean = true
Start the panel expanded. Collapse it to read the turn behind it.
skipLabelstring = "Skip"
Label on the secondary action.
submitLabelstring = "Continue"
Label on the primary action.

AskQuestionSummary

questions*AskQuestionItem[]
The same questions the answer was collected for.
result*AskQuestionResult
Settled answer. skipped: true renders the one-line skipped note instead.
hideOtherboolean = false
Match the AskQuestion setting so labels resolve.

Data slots

Every part below is addressable from a parent, so you can restyle internals without forking the component.

ask-questionask-question-triggerask-question-formask-question-itemask-question-promptask-question-groupask-question-optionask-question-indicatorask-question-otherask-question-actionsask-question-skipask-question-submitask-question-summary