suiss/ui · Component
Questionnaire
A step-by-step form that shows one question at a time, with validation, skipping and keyboard shortcuts.
Questionnaire is an open-source component from suiss/ui for React, React Native, SwiftUI and Jetpack Compose. The @esuiss/ui CLI copies its source into your project, so you own the code.
Questionnaire renders a form that presents a sequence of questions, one at a time. Each QuestionnaireItem is a fieldset with a QuestionnaireTitle, an optional QuestionnaireDescription, an answer area and a QuestionnaireError. Answers are either QuestionnaireChoices holding QuestionnaireChoice cards (with optional QuestionnaireChoiceDescription), or a QuestionnaireInput.
QuestionnaireProgress shows the current position, and QuestionnaireActions lays out QuestionnairePrevious, QuestionnaireSkip, QuestionnaireNext and QuestionnaireSubmit, which show and hide themselves based on the current question. Use Questionnaire for onboarding flows and surveys; use Field and regular form controls when all fields should be visible at once.
Installation
CLI
Works in any project with a components.json. See Installation for the one-line registry setup. Or use the suiss/ui CLI:
Manual
- Install the dependencies and add the
cnhelper:
-
Add the pieces it builds on: Button,
use-questionnaire. -
Copy the source into
components/ui/questionnaire.tsx:
- Update the import paths to match your project.
Usage
Give every item a unique name; answers are submitted as form data under that name. The first item is shown by default. Use defaultItem to start elsewhere, or item with onItemChange to control the active question.
A required item blocks Next and Submit until it is answered. An optional item shows the Skip button. Set multiple on an item to render its choices as checkboxes instead of radio buttons.
Pass items to define the sequence, which items are required or disabled, and the order used for shortcut keys, instead of deriving them from the rendered items. Native browser validation is off by default (noValidate); the component runs its own validation on Next and Submit.
Examples
With shortcuts
Choices labelled with letter keys, so pressing a letter selects the matching answer.
Number shortcuts
Choices labelled with number keys from 1 to 9.
Multiple choice
A multiple item with checkboxes, a default selection, a disabled choice and a custom error.
With choice descriptions
Choice cards with a title and a secondary description.
Text input
A required email question answered with QuestionnaireInput.
Start on later question
A questionnaire that opens on its second question with defaultItem.
API Reference
Questionnaire
The form root that tracks the active question and handles navigation and submission.
| Prop | Type | Default | Description |
|---|---|---|---|
defaultItem | string | - | The name of the item shown first when uncontrolled. |
item | string | - | The name of the active item, for controlled use. |
items | readonly QuestionnaireItemDefinition[] | - | Optional item definitions with name, required, disabled and choices, used to define the sequence and shortcut order. |
onItemChange | (item: string) => void | - | Called with the next item's name when the active question changes. |
shortcuts | QuestionnaireShortcutMode | - | Enables single-key answer shortcuts using letters (A to Z) or numbers (1 to 9). |
Also accepts the props of React.ComponentProps<"form">.
QuestionnaireProgress
Shows the position as text, such as Question 2 of 3, and exposes it to assistive technology with the progressbar role.
Also accepts the props of useRender.ComponentProps<"div", QuestionnaireState>.
QuestionnaireItem
A fieldset for one question, visible only while it is active.
| Prop | Type | Default | Description |
|---|---|---|---|
invalid | boolean | false | Forces the item into the invalid state. |
multiple | boolean | false | Allows several answers, rendering choices as checkboxes. |
name | string | Required | The unique item name, used for navigation and as the form field name. |
onStatusChange | (status: QuestionnaireItemStatus) => void | - | Called when the item's status changes between unanswered, answered and skipped. |
required | boolean | false | Requires an answer before moving on and hides the Skip button. |
Also accepts the props of React.ComponentProps<"fieldset">.
QuestionnaireTitle
The question text, rendered as the fieldset's legend.
Also accepts the props of useRender.ComponentProps<"legend">.
QuestionnaireDescription
Supporting text that describes the question.
Also accepts the props of useRender.ComponentProps<"p">.
QuestionnaireChoices
The grid that holds the answer choices.
Also accepts the props of useRender.ComponentProps< "div", { shortcuts: QuestionnaireShortcutMode | null } >.
QuestionnaireChoice
A selectable answer card containing a radio button or checkbox.
| Prop | Type | Default | Description |
|---|---|---|---|
checked | boolean | - | The checked state, for controlled use. |
defaultChecked | boolean | false | Whether the choice starts checked when uncontrolled. |
disabled | boolean | false | Prevents the choice from being selected. |
onChange | React.ChangeEventHandler<HTMLInputElement> | - | Called when the underlying input changes. |
value | string | Required | The value submitted for this choice. |
Also accepts the props of useRender.ComponentProps<"label", QuestionnaireChoiceState>.
QuestionnaireChoiceDescription
Secondary text inside a choice that describes it.
Also accepts the props of React.ComponentProps<"span">.
QuestionnaireInput
A text-style input for free-form answers.
| Prop | Type | Default | Description |
|---|---|---|---|
type | QuestionnaireInputType | "text" | The input type, such as text, email, number, date or url. |
Also accepts the props of useRender.ComponentProps<"input", QuestionnaireInputState>.
QuestionnaireError
The validation message shown when the question needs an answer.
Also accepts the props of useRender.ComponentProps<"p", { invalid: boolean }>.
QuestionnaireActions
Lays out the navigation buttons in one row.
Also accepts the props of React.ComponentProps<"div">.
QuestionnairePrevious
Goes back to the previous question; hidden on the first.
Also accepts the props of QuestionnaireNavigationProps.
QuestionnaireSkip
Skips the current optional question; hidden when the question is required.
Also accepts the props of QuestionnaireNavigationProps.
QuestionnaireNext
Validates the current question and moves to the next; hidden on the last.
Also accepts the props of QuestionnaireNavigationProps.
QuestionnaireSubmit
Submits the form; shown only on the last question.
Also accepts the props of QuestionnaireNavigationProps.
Accessibility
- Each item is a
fieldsetnamed by itslegendtitle; inactive items arehiddenandinert. - Choices are native radio buttons or checkboxes inside a
label. A choice description is linked witharia-describedby. QuestionnaireInputis labelled by the question title unless you passaria-label.- The item's description and, when invalid, its error are linked with
aria-describedby. The error usesrole="alert"and focus moves to the invalid answer. QuestionnaireProgresshasrole="progressbar", anaria-labelofQuestionnaire progress,aria-valuetextandaria-live="polite".- Keyboard: Enter on an answered control advances or submits; Command or Control plus Enter advances from anywhere; ArrowUp and ArrowDown move between answers; outside text fields and radio buttons, ArrowLeft goes back and ArrowRight goes forward once the question has an answer. The active item lists these in
aria-keyshortcuts. - Hidden navigation buttons are
aria-hidden,inertand removed from the tab order.
Notes
- Styling hooks: every part sets a
data-slot, such asquestionnaire,questionnaire-item,questionnaire-choice,questionnaire-choice-indicator,questionnaire-choice-shortcut,questionnaire-inputandquestionnaire-error. - Choices expose
data-checkedordata-unchecked, plusdata-type,data-disabled,data-invalidanddata-shortcut. Inputs exposedata-filledordata-empty. Navigation buttons exposedata-visibleordata-hidden. - Shortcut badges are hidden below the
mdbreakpoint. - The default error text is
Choose an answer to continue.for required items; pass children to customize it. - Uses the
primary,border,secondary,destructiveandaccentcolors.
Questionnaire is a View that tracks which question is active, collects answers and validates them. Each QuestionnaireItem is one question; only the active item is shown, and moving between items slides the content horizontally with a Reanimated keyframe that follows the layout direction.
Items hold QuestionnaireChoice rows, which are Pressable radios or, with multiple, checkboxes, or a QuestionnaireInput for a typed answer. QuestionnaireActions holds the Previous, Skip, Next and Submit buttons, each of which only appears when it applies.











