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.
Usage
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: aform.itemssets the step order and choice shortcuts; without it, rendered items are used in order.defaultItem, oritemwithonItemChange, picks the shown step. Aresetclears answers and returns to the first step.QuestionnaireItem: one question, afieldset.requiredhides Skip,multipleuses checkboxes,disableddrops it from the steps,invalidforces the error, andonStatusChangereportsunanswered,answered, orskipped.QuestionnaireChoice:value, plusdefaultCheckedorchecked,disabled, andonChange.QuestionnaireChoiceDescriptionadds 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 Buttonsizeandvariant.
Keyboard shortcuts
shortcuts="letters" or "numbers" shows a key on each enabled choice. With items, keys follow its order and skip disabled choices.
shortcuts="letters" with items
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.
Required, shown invalid until fixed
Disabled item is left out of the steps
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.
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.
Current step: goal
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.