Questionnaire
AIStructured questions an assistant asks before it acts, one step at a time, with keyboard shortcuts for the choices.
npx prodular-ui add questionnaireClarifying questions
Two steps with progress. Number keys pick a choice and Enter moves on.
Copilot needs two answers before it forecasts
"use client"
import * as React from "react"
import { AiMark } from "@/components/ui/ai-mark"import { Questionnaire, QuestionnaireActions, QuestionnaireChoice, QuestionnaireChoiceDescription, QuestionnaireChoices, QuestionnaireDescription, QuestionnaireItem, QuestionnaireNext, QuestionnaireProgress, QuestionnaireSkip, QuestionnaireSubmit, QuestionnaireTitle,} from "@/components/ui/questionnaire"
export default function QuestionnaireClarify() { const [sent, setSent] = React.useState(false) if (sent) { return ( <p className="text-sm text-muted-foreground"> Thanks. Building the forecast with those assumptions. </p> ) } return ( <div className="w-full max-w-md rounded-xl border bg-card p-5 shadow-xs"> <div className="mb-4 flex items-center gap-2 text-[13px] text-muted-foreground"> <AiMark /> Copilot needs two answers before it forecasts </div> <Questionnaire shortcuts="numbers" onSubmit={(event) => { event.preventDefault() setSent(true) }} > <QuestionnaireProgress /> <QuestionnaireItem name="horizon" required> <QuestionnaireTitle>How far ahead should the cash forecast go?</QuestionnaireTitle> <QuestionnaireChoices> <QuestionnaireChoice value="13w"> 13 weeks <QuestionnaireChoiceDescription>Weekly detail, best for treasury.</QuestionnaireChoiceDescription> </QuestionnaireChoice> <QuestionnaireChoice value="6m"> 6 months <QuestionnaireChoiceDescription>Monthly, includes the January price rise.</QuestionnaireChoiceDescription> </QuestionnaireChoice> <QuestionnaireChoice value="12m">12 months</QuestionnaireChoice> </QuestionnaireChoices> <QuestionnaireActions> <QuestionnaireNext /> </QuestionnaireActions> </QuestionnaireItem> <QuestionnaireItem name="hires"> <QuestionnaireTitle>Include the open roles in payroll?</QuestionnaireTitle> <QuestionnaireDescription>Six roles are approved but not filled.</QuestionnaireDescription> <QuestionnaireChoices> <QuestionnaireChoice value="all">Yes, from their target start dates</QuestionnaireChoice> <QuestionnaireChoice value="none">No, current headcount only</QuestionnaireChoice> </QuestionnaireChoices> <QuestionnaireActions> <QuestionnaireSkip /> <QuestionnaireSubmit>Build forecast</QuestionnaireSubmit> </QuestionnaireActions> </QuestionnaireItem> </Questionnaire> </div> )}Multiple choice with a note
Checkboxes plus a free text field for anything the choices miss.
import { Questionnaire, QuestionnaireActions, QuestionnaireChoice, QuestionnaireChoices, QuestionnaireDescription, QuestionnaireInput, QuestionnaireItem, QuestionnaireSubmit, QuestionnaireTitle,} from "@/components/ui/questionnaire"
export default function QuestionnaireMultiple() { return ( <div className="w-full max-w-md rounded-xl border bg-card p-5 shadow-xs"> <Questionnaire shortcuts="letters"> <QuestionnaireItem name="entities" multiple required> <QuestionnaireTitle>Which entities should the consolidation cover?</QuestionnaireTitle> <QuestionnaireDescription>Pick all that apply.</QuestionnaireDescription> <QuestionnaireChoices> <QuestionnaireChoice value="us" defaultChecked>Ledgerline Inc. (US)</QuestionnaireChoice> <QuestionnaireChoice value="uk" defaultChecked>Ledgerline Ltd. (UK)</QuestionnaireChoice> <QuestionnaireChoice value="nl">Ledgerline B.V. (Netherlands)</QuestionnaireChoice> </QuestionnaireChoices> <QuestionnaireInput placeholder="Anything else Copilot should know" /> <QuestionnaireActions> <QuestionnaireSubmit>Continue</QuestionnaireSubmit> </QuestionnaireActions> </QuestionnaireItem> </Questionnaire> </div> )}Anatomy
<Questionnaire onSubmit={send}> <QuestionnaireItem name="horizon" required> <QuestionnaireTitle>How far ahead?</QuestionnaireTitle> <QuestionnaireChoices> <QuestionnaireChoice value="13w">13 weeks</QuestionnaireChoice> </QuestionnaireChoices> <QuestionnaireActions><QuestionnaireSubmit /></QuestionnaireActions> </QuestionnaireItem></Questionnaire>Guidance
Use it when
- When the assistant needs a decision before a long or costly task: a forecast, a migration, sending emails.
- Two to four choices per question, each a complete answer.
Avoid
- Asking what the assistant could look up itself.
- More than three questions. Ask the rest later or pick defaults and say so.
Rules for AI agents
Published in llms-full.txt, the registry and the MCP server, so coding agents follow them when they build with this component.
- Render the questionnaire inside the assistant Message that asks it, not as a modal.
- Give every QuestionnaireItem a unique name and mark required items. Use multiple for checkbox questions.
- Write titles as questions ending in a question mark, and choices as answers, not as Yes or No alone.
- On submit, send the answers back as a user message so the thread keeps a record of what was chosen.
API
Questionnaire
| Prop | Type | Default | Description |
|---|---|---|---|
| shortcuts | "letters" | "numbers" | Keyboard shortcuts for choices. | |
| onSubmit | FormEventHandler | Called when the last step is sent. |
QuestionnaireItem
| Prop | Type | Default | Description |
|---|---|---|---|
| name / required / multiple | string, boolean, boolean | One question. |
QuestionnaireChoice
| Prop | Type | Default | Description |
|---|---|---|---|
| value | string | Choice value. |
Installation
The Prodular UI CLI adds the source to components/ui with everything it depends on. In a project that already uses shadcn/ui, the shadcn CLI installs it from the Prodular registry too. See Installation for the first setup.
npx prodular-ui add questionnaire# or, with the registry in components.jsonnpx shadcn@latest add @prodular/questionnaire