Questionnaire
A form that asks one question at a time, with validation, skipping and keyboard shortcuts.
Questionnaire ports the questionnaire of @shadcn/react v0.3.1. It follows that package, not Base UI.
Anatomy
Import the component and assemble its parts:
Server rendering
Pass items to Root to render the active item, the progress and the shortcuts on the server. Without it, Root learns the items as they mount.
Keyboard
- Enter on an answer moves to the next item, or submits from the last one.
- Ctrl+Enter or Cmd+Enter does the same from anywhere in the item.
- ArrowUp and ArrowDown move between answers.
- ArrowLeft and ArrowRight move between items, outside text fields and radios.
- With
shortcuts, a letter or a number selects its choice.
API reference
Root
A form that shows one item at a time and validates each before it moves on. Renders a <form> element.
defaultItem string —
- Name
- Description
The item to start on when
itemis undefined. Defaults to the first enabled item.- Type
string
item string —
- Name
- Description
The active item name. Bind it to follow and set navigation.
- Type
string- Binding
bind:item
items readonly QuestionnaireItemDefinition[] —
- Name
- Description
Item order, required flags and choice values, so the server renders the active item, progress and shortcuts.
- Type
readonly QuestionnaireItemDefinition[]
novalidate boolean true
- Name
- Description
Turns off the browser's constraint validation UI. Questionnaire validation still runs.
- Type
boolean- Default
true
onItemChange function —
- Name
- Description
Called when navigation moves to another item.
- Type
(item: string) => void
shortcuts QuestionnaireShortcutMode —
- Name
- Description
Gives each choice a letter or number key that selects it.
- Type
QuestionnaireShortcutMode
current number
- Name
current- Description
The 1-based position of the active item, or 0 when no item is enabled.
- Type
number
first boolean
- Name
first- Description
Whether the first item is active.
- Type
boolean
last boolean
- Name
last- Description
Whether the last item is active.
- Type
boolean
total number
- Name
total- Description
The number of enabled items.
- Type
number
data-current
data-first
data-last
data-shortcuts
letters or numbers, when shortcuts are on.data-total
Progress
Shows the position of the active item among the enabled items. Renders a <div> element.
children Snippet —
- Name
- Description
Defaults to "Question {current} of {total}".
- Type
Snippet
render Snippet<[props: HTMLAttributes<HTMLElement>, state: QuestionnaireProgressState, children: Snippet | undefined]> —
- Name
- Description
Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a snippet that receives the props to spread onto the element, the component's state, and the children to render.
- Type
Snippet<[props: HTMLAttributes<HTMLElement>, state: QuestionnaireProgressState, children: Snippet | undefined]>
current number
- Name
current- Description
The 1-based position of the active item, or 0 when no item is enabled.
- Type
number
first boolean
- Name
first- Description
Whether the first item is active.
- Type
boolean
last boolean
- Name
last- Description
Whether the last item is active.
- Type
boolean
total number
- Name
total- Description
The number of enabled items.
- Type
number
data-current
data-first
data-last
data-total
Item
One step of the questionnaire, hidden while another step is active. Renders a <fieldset> element.
name* string —
- Name
- Description
Unique within the questionnaire, and the form field name of its answers.
- Type
string
multiple boolean false
- Name
- Description
Renders fixed choices as checkboxes.
- Type
boolean- Default
false
onStatusChange function —
- Name
- Description
Called when the item becomes answered, skipped or unanswered.
- Type
(status: QuestionnaireItemStatus) => void
disabled boolean false
- Name
- Description
Removes the item from progress, navigation, validation and submission.
- Type
boolean- Default
false
required boolean false
- Name
- Description
Whether the item needs an answer. A required item cannot be skipped.
- Type
boolean- Default
false
invalid boolean false
- Name
- Description
Marks the item invalid from an external validator.
- Type
boolean- Default
false
active boolean
- Name
active- Description
Whether the item is the active one.
- Type
boolean
disabled boolean
- Name
disabled- Description
Whether the item is disabled.
- Type
boolean
invalid boolean
- Name
invalid- Description
Whether the item failed validation or
invalidis set.- Type
boolean
multiple boolean
- Name
multiple- Description
Whether the item takes more than one choice.
- Type
boolean
required boolean
- Name
required- Description
Whether the item needs an answer.
- Type
boolean
status QuestionnaireItemStatus
- Name
status- Description
Whether the item is answered, skipped or neither.
- Type
QuestionnaireItemStatus
data-disabled
data-required
data-invalid
invalid is set.data-active
data-multiple
data-status
unanswered, answered or skipped.Title
The item title. Renders a <legend> element.
render Snippet<[props: HTMLAttributes<HTMLElement>, state: Record<string, never>, children: Snippet | undefined]> —
- Name
- Description
Replaces the
<legend>. Give it anidand pass that to the Item'saria-labelledby.- Type
Snippet<[props: HTMLAttributes<HTMLElement>, state: Record<string, never>, children: Snippet | undefined]>
Description
Supporting text that describes the item. Renders a <p> element.
render Snippet<[props: HTMLAttributes<HTMLElement>, state: Record<string, never>, children: Snippet | undefined]> —
- Name
- Description
Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a snippet that receives the props to spread onto the element, the component's state, and the children to render.
- Type
Snippet<[props: HTMLAttributes<HTMLElement>, state: Record<string, never>, children: Snippet | undefined]>
Choices
Groups the answers of an item. Renders a <div> element.
render Snippet<[props: HTMLAttributes<HTMLElement>, state: QuestionnaireChoicesState, children: Snippet | undefined]> —
- Name
- Description
Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a snippet that receives the props to spread onto the element, the component's state, and the children to render.
- Type
Snippet<[props: HTMLAttributes<HTMLElement>, state: QuestionnaireChoicesState, children: Snippet | undefined]>
shortcuts QuestionnaireShortcutMode | null
- Name
shortcuts- Description
The shortcut mode, or null when shortcuts are off.
- Type
QuestionnaireShortcutMode | null
data-shortcuts
letters or numbers, when shortcuts are on.Choice
A fixed answer, with its native control inside. Renders a <label> element.
defaultChecked boolean —
- Name
- Description
The state a form reset restores. Defaults to the initial
checked.- Type
boolean
checked boolean —
- Name
- Description
Bind it to follow and set the selection.
- Type
boolean- Binding
bind:checked
value* string —
- Name
- Description
The value the choice submits.
- Type
string
onchange ChangeEventHandler<HTMLInputElement> | null —
- Name
- Description
Runs for the native input's change event.
- Type
ChangeEventHandler<HTMLInputElement> | null
disabled boolean false
- Name
- Description
Whether the choice ignores user interaction.
- Type
boolean- Default
false
render Snippet<[props: HTMLAttributes<HTMLElement>, state: QuestionnaireChoiceState, children: Snippet | undefined]> —
- Name
- Description
Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a snippet that receives the props to spread onto the element, the component's state, and the children to render.
- Type
Snippet<[props: HTMLAttributes<HTMLElement>, state: QuestionnaireChoiceState, children: Snippet | undefined]>
checked boolean
- Name
checked- Description
Whether the choice is selected.
- Type
boolean
disabled boolean
- Name
disabled- Description
Whether the choice or its item is disabled.
- Type
boolean
invalid boolean
- Name
invalid- Description
Whether its item is invalid.
- Type
boolean
shortcut string | null
- Name
shortcut- Description
The key that selects the choice, or null.
- Type
string | null
type 'checkbox' | 'radio'
- Name
type- Description
The native control type. A multiple item renders checkboxes.
- Type
'checkbox' | 'radio'
data-checked
data-unchecked
data-disabled
data-invalid
data-shortcut
data-type
radio, or checkbox in a multiple item.ChoiceInput
The native radio or checkbox of a choice. Renders an <input> element.
render Snippet<[props: HTMLInputAttributes, state: QuestionnaireChoiceState]> —
- Name
- Description
Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a snippet that receives the props to spread onto the element and the component's state.
- Type
Snippet<[props: HTMLInputAttributes, state: QuestionnaireChoiceState]>
checked boolean
- Name
checked- Description
Whether the choice is selected.
- Type
boolean
disabled boolean
- Name
disabled- Description
Whether the choice or its item is disabled.
- Type
boolean
invalid boolean
- Name
invalid- Description
Whether its item is invalid.
- Type
boolean
shortcut string | null
- Name
shortcut- Description
The key that selects the choice, or null.
- Type
string | null
type 'checkbox' | 'radio'
- Name
type- Description
The native control type. A multiple item renders checkboxes.
- Type
'checkbox' | 'radio'
data-checked
data-unchecked
data-disabled
data-invalid
data-shortcut
data-type
radio, or checkbox in a multiple item.ChoiceLabel
The text of a choice. Renders a <span> element.
render Snippet<[props: HTMLAttributes<HTMLElement>, state: Record<string, never>, children: Snippet | undefined]> —
- Name
- Description
Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a snippet that receives the props to spread onto the element, the component's state, and the children to render.
- Type
Snippet<[props: HTMLAttributes<HTMLElement>, state: Record<string, never>, children: Snippet | undefined]>
ChoiceShortcut
Shows the key that selects a choice. Renders a <span> element.
children Snippet —
- Name
- Description
Defaults to the assigned shortcut.
- Type
Snippet
render Snippet<[props: HTMLAttributes<HTMLElement>, state: QuestionnaireChoiceShortcutState, children: Snippet | undefined]> —
- Name
- Description
Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a snippet that receives the props to spread onto the element, the component's state, and the children to render.
- Type
Snippet<[props: HTMLAttributes<HTMLElement>, state: QuestionnaireChoiceShortcutState, children: Snippet | undefined]>
shortcut string | null
- Name
shortcut- Description
The key that selects the choice, or null.
- Type
string | null
data-shortcut
Input
A freeform answer, named by its item. Renders an <input> element.
defaultValue string | number | null —
- Name
- Description
The value a form reset restores. Defaults to the initial
value.- Type
string | number | null
value string | number | null —
- Name
- Description
Bind it to follow and set the text. A number input holds a number, or null when empty.
- Type
string | number | null- Binding
bind:value
type QuestionnaireInputType 'text'
- Name
- Description
A text-entry input type, such as
email,numberordate.- Type
QuestionnaireInputType- Default
'text'
disabled boolean false
- Name
- Description
Whether the input ignores user interaction.
- Type
boolean- Default
false
render Snippet<[props: HTMLInputAttributes, state: QuestionnaireInputState]> —
- Name
- Description
Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a snippet that receives the props to spread onto the element and the component's state.
- Type
Snippet<[props: HTMLInputAttributes, state: QuestionnaireInputState]>
disabled boolean
- Name
disabled- Description
Whether the input or its item is disabled.
- Type
boolean
filled boolean
- Name
filled- Description
Whether the input holds text.
- Type
boolean
invalid boolean
- Name
invalid- Description
Whether its item is invalid.
- Type
boolean
data-disabled
data-invalid
data-empty
data-filled
Error
The validation message, hidden until the item fails validation. Renders a <p> element.
children Snippet —
- Name
- Description
Defaults to a message that depends on whether the item is required.
- Type
Snippet
render Snippet<[props: HTMLAttributes<HTMLElement>, state: QuestionnaireErrorState, children: Snippet | undefined]> —
- Name
- Description
Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a snippet that receives the props to spread onto the element, the component's state, and the children to render.
- Type
Snippet<[props: HTMLAttributes<HTMLElement>, state: QuestionnaireErrorState, children: Snippet | undefined]>
invalid boolean
- Name
invalid- Description
Whether its item is invalid.
- Type
boolean
data-invalid
Previous
Moves to the previous item. Renders a <button> element.
children Snippet —
- Name
- Description
Defaults to the action's name, such as "Next".
- Type
Snippet
render Snippet<[props: HTMLButtonAttributes, state: QuestionnaireNavigationState, children: Snippet | undefined]> —
- Name
- Description
Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a snippet that receives the props to spread onto the element, the component's state, and the children to render.
- Type
Snippet<[props: HTMLButtonAttributes, state: QuestionnaireNavigationState, children: Snippet | undefined]>
disabled boolean
- Name
disabled- Description
Whether the button is disabled.
- Type
boolean
shortcut 'Enter' | null
- Name
shortcut- Description
Enteron an enabled, visible Next or Submit.- Type
'Enter' | null
status QuestionnaireItemStatus | null
- Name
status- Description
The active item's status, or null when no item is active.
- Type
QuestionnaireItemStatus | null
visible boolean
- Name
visible- Description
Whether the action applies to the active item.
- Type
boolean
data-disabled
data-hidden
data-shortcut
Enter on an enabled, visible Next or Submit.data-status
unanswered, answered or skipped.data-visible
Skip
Skips an optional item. Renders a <button> element.
children Snippet —
- Name
- Description
Defaults to the action's name, such as "Next".
- Type
Snippet
render Snippet<[props: HTMLButtonAttributes, state: QuestionnaireNavigationState, children: Snippet | undefined]> —
- Name
- Description
Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a snippet that receives the props to spread onto the element, the component's state, and the children to render.
- Type
Snippet<[props: HTMLButtonAttributes, state: QuestionnaireNavigationState, children: Snippet | undefined]>
disabled boolean
- Name
disabled- Description
Whether the button is disabled.
- Type
boolean
shortcut 'Enter' | null
- Name
shortcut- Description
Enteron an enabled, visible Next or Submit.- Type
'Enter' | null
status QuestionnaireItemStatus | null
- Name
status- Description
The active item's status, or null when no item is active.
- Type
QuestionnaireItemStatus | null
visible boolean
- Name
visible- Description
Whether the action applies to the active item.
- Type
boolean
data-disabled
data-hidden
data-shortcut
Enter on an enabled, visible Next or Submit.data-status
unanswered, answered or skipped.data-visible
Next
Validates the active item and moves to the next one. Renders a <button> element.
children Snippet —
- Name
- Description
Defaults to the action's name, such as "Next".
- Type
Snippet
render Snippet<[props: HTMLButtonAttributes, state: QuestionnaireNavigationState, children: Snippet | undefined]> —
- Name
- Description
Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a snippet that receives the props to spread onto the element, the component's state, and the children to render.
- Type
Snippet<[props: HTMLButtonAttributes, state: QuestionnaireNavigationState, children: Snippet | undefined]>
disabled boolean
- Name
disabled- Description
Whether the button is disabled.
- Type
boolean
shortcut 'Enter' | null
- Name
shortcut- Description
Enteron an enabled, visible Next or Submit.- Type
'Enter' | null
status QuestionnaireItemStatus | null
- Name
status- Description
The active item's status, or null when no item is active.
- Type
QuestionnaireItemStatus | null
visible boolean
- Name
visible- Description
Whether the action applies to the active item.
- Type
boolean
data-disabled
data-hidden
data-shortcut
Enter on an enabled, visible Next or Submit.data-status
unanswered, answered or skipped.data-visible
Submit
Submits the form from the last item. Renders a <button> element.
children Snippet —
- Name
- Description
Defaults to the action's name, such as "Next".
- Type
Snippet
render Snippet<[props: HTMLButtonAttributes, state: QuestionnaireNavigationState, children: Snippet | undefined]> —
- Name
- Description
Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a snippet that receives the props to spread onto the element, the component's state, and the children to render.
- Type
Snippet<[props: HTMLButtonAttributes, state: QuestionnaireNavigationState, children: Snippet | undefined]>
disabled boolean
- Name
disabled- Description
Whether the button is disabled.
- Type
boolean
shortcut 'Enter' | null
- Name
shortcut- Description
Enteron an enabled, visible Next or Submit.- Type
'Enter' | null
status QuestionnaireItemStatus | null
- Name
status- Description
The active item's status, or null when no item is active.
- Type
QuestionnaireItemStatus | null
visible boolean
- Name
visible- Description
Whether the action applies to the active item.
- Type
boolean
data-disabled
data-hidden
data-shortcut
Enter on an enabled, visible Next or Submit.data-status
unanswered, answered or skipped.