ComponentsAI & chat

Questionnaire

A form that asks one question at a time. Each item holds radio or checkbox choices, or a typed answer. Next checks required answers, Skip clears optional ones, and the last item submits the form.

Multi-step questionnaireAnswers stay in the local form. Nothing is submitted to a service.
Question 1 of 3
How should answers look?

Pick one reply style.

Usage

A three-step questionnaireTSX
import {
  Questionnaire,
  QuestionnaireActions,
  QuestionnaireChoice,
  QuestionnaireChoiceDescription,
  QuestionnaireChoices,
  QuestionnaireDescription,
  QuestionnaireError,
  QuestionnaireInput,
  QuestionnaireItem,
  QuestionnaireNext,
  QuestionnairePrevious,
  QuestionnaireProgress,
  QuestionnaireSkip,
  QuestionnaireSubmit,
  QuestionnaireTitle,
} from "@tulipfarm/sprout/questionnaire";

<Questionnaire
  items={[
    { name: "style", required: true, choices: [{ value: "short" }, { value: "detailed" }] },
    { name: "plants", choices: [{ value: "tulips" }, { value: "daisies" }] },
    { name: "note" },
  ]}
  onSubmit={(event) => {
    event.preventDefault();
    save(new FormData(event.currentTarget));
  }}
>
  <QuestionnaireProgress />
  <QuestionnaireItem name="style" required>
    <QuestionnaireTitle>How should answers look?</QuestionnaireTitle>
    <QuestionnaireDescription>Pick one reply style.</QuestionnaireDescription>
    <QuestionnaireChoices>
      <QuestionnaireChoice value="short">
        Short answers
        <QuestionnaireChoiceDescription>A quick summary.</QuestionnaireChoiceDescription>
      </QuestionnaireChoice>
      <QuestionnaireChoice value="detailed">Detailed answers</QuestionnaireChoice>
    </QuestionnaireChoices>
    <QuestionnaireError>Choose a reply style.</QuestionnaireError>
  </QuestionnaireItem>
  <QuestionnaireItem name="plants" multiple>…</QuestionnaireItem>
  <QuestionnaireItem name="note">
    <QuestionnaireTitle>Anything else?</QuestionnaireTitle>
    <QuestionnaireInput aria-label="Additional note" value={note} onChange={…} />
  </QuestionnaireItem>
  <QuestionnaireActions>
    <QuestionnairePrevious />
    <QuestionnaireSkip />
    <QuestionnaireNext />
    <QuestionnaireSubmit />
  </QuestionnaireActions>
  <Button type="reset" variant="outline">Restart</Button>
</Questionnaire>

  • Questionnaire: a form. itemssets the step order and choice shortcuts; without it, rendered items are used in order. defaultItem, or itemwith onItemChange, picks the shown step. Areset clears answers and returns to the first step.
  • QuestionnaireItem: one question, afieldset. required hides Skip,multiple uses checkboxes, disabled drops it from the steps, invalid forces the error, andonStatusChange reports unanswered,answered, or skipped.
  • QuestionnaireChoice: value, plusdefaultChecked or checked,disabled, and onChange.QuestionnaireChoiceDescription adds a muted line.
  • QuestionnaireInput: a typed answer (text,email, number, date, and more). It is sent with the form only while it has text.
  • QuestionnaireError: hidden until someone tries to move on without an answer. Its default text depends onrequired.
  • QuestionnairePrevious, QuestionnaireSkip,QuestionnaireNext, QuestionnaireSubmit: each shows only when it applies. They take Buttonsize and variant.

Keyboard shortcuts

shortcuts="letters" or "numbers" shows a key on each enabled choice. With items, keys follow its order and skip disabled choices.

Keyboard shortcutsPress a key to pick a choice. Enter moves on once answered.

shortcuts="letters" with items

Question 1 of 2
Which model should draft the reply?

shortcuts="numbers" in rendered order

States

A required item shows its error and stays put until answered. A disabled item is left out of the count. Skipping an optional last question submits the form.

StatesErrors, disabled items and choices, a typed email, and a single question.

Required, shown invalid until fixed

Disabled item is left out of the steps

First item: unanswered

One optional question

Action sizes

By default Previous and Skip are outline and Next and Submit are default, at the default size. Inside a dense chat reply, sm with ghostback buttons fits better.

Action sizesNavigation buttons take Button size and variant.

default size: outline back and skip, default next

sm size: ghost back and skip, for chat replies

Controlled step

Pass item and onItemChange to keep the step in your own state. Focus moves to the shown item when it changes.

Controlled stepitem and onItemChange keep the step in your state.

Current step: goal

What is the garden for?

Accessibility

Each item is a fieldset named by its legendtitle and described by its description and, while shown, its error (role="alert"). Hidden items and buttons areinert. Progress is a progressbar that announces "Question 2 of 3".

Keys: ↑↓ move between answers, Enteron an answer moves on, ⌘/Ctrl + Entermoves on from anywhere, and ←→ go back or forward outside text fields. Each control lists its keys inaria-keyshortcuts.

The shown item fades in over 160ms and marks pop in over 140ms; with reduced motion both change at once. Rows are 44px tall, and on phones buttons and the text field are too.

Theme tokens

Rows use --sprout-input borders, and a picked row uses--sprout-focus and --sprout-primary-subtlewith a --sprout-primary mark. Errors use--sprout-danger; help text uses--sprout-muted.