Skip to contents

Questionnaire

A form that asks one question at a time, with validation, skipping and keyboard shortcuts.

Question 1 of 2
Pick a size

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:

Anatomy

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 —
Description

The item to start on when item is 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
Description

Turns off the browser's constraint validation UI. Questionnaire validation still runs.

Type
boolean
Default
true
onItemChange function —
Description

Called when navigation moves to another item.

Type
(item: string) => void
shortcuts QuestionnaireShortcutMode —
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
The 1-based position of the active item.
data-first
Present when the first item is active.
data-last
Present when the last item is active.
data-shortcuts
The shortcut mode, letters or numbers, when shortcuts are on.
data-total
The number of enabled items.

Progress

Shows the position of the active item among the enabled items. Renders a <div> element.

children Snippet —
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
The 1-based position of the active item.
data-first
Present when the first item is active.
data-last
Present when the last item is active.
data-total
The number of enabled items.

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
Description

Renders fixed choices as checkboxes.

Type
boolean
Default
false
onStatusChange function —
Description

Called when the item becomes answered, skipped or unanswered.

Type
(status: QuestionnaireItemStatus) => void
disabled boolean false
Description

Removes the item from progress, navigation, validation and submission.

Type
boolean
Default
false
required boolean false
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 invalid is 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
Present when the item is disabled.
data-required
Present when the item needs an answer.
data-invalid
Present when the item failed validation or invalid is set.
data-active
Present when the item is the active one.
data-multiple
Present when the item takes more than one choice.
data-status
The answer 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 an id and pass that to the Item's aria-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
The shortcut mode, letters or numbers, when shortcuts are on.

Choice

A fixed answer, with its native control inside. Renders a <label> element.

defaultChecked boolean —
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 —
Description

Runs for the native input's change event.

Type
ChangeEventHandler<HTMLInputElement> | null
disabled boolean false
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
Present when the choice is selected.
data-unchecked
Present when the choice is not selected.
data-disabled
Present when the choice is disabled.
data-invalid
Present when its item is invalid.
data-shortcut
The key that selects the choice.
data-type
The control 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
Present when the choice is selected.
data-unchecked
Present when the choice is not selected.
data-disabled
Present when the choice is disabled.
data-invalid
Present when its item is invalid.
data-shortcut
The key that selects the choice.
data-type
The control 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 —
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
The key that selects the choice.

Input

A freeform answer, named by its item. Renders an <input> element.

defaultValue string | number | null —
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, number or date.

Type
QuestionnaireInputType
Default
'text'
disabled boolean false
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
Present when the input is disabled.
data-invalid
Present when its item is invalid.
data-empty
Present when the input is empty.
data-filled
Present when the input holds text.

Error

The validation message, hidden until the item fails validation. Renders a <p> element.

children Snippet —
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
Present while its item is invalid.

Previous

Moves to the previous item. Renders a <button> element.

children Snippet —
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

Enter on 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
Present when the button is disabled.
data-hidden
Present when the action does not apply to the active item.
data-shortcut
Enter on an enabled, visible Next or Submit.
data-status
The active item's status: unanswered, answered or skipped.
data-visible
Present when the action applies to the active item.

Skip

Skips an optional item. Renders a <button> element.

children Snippet —
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

Enter on 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
Present when the button is disabled.
data-hidden
Present when the action does not apply to the active item.
data-shortcut
Enter on an enabled, visible Next or Submit.
data-status
The active item's status: unanswered, answered or skipped.
data-visible
Present when the action applies to the active item.

Next

Validates the active item and moves to the next one. Renders a <button> element.

children Snippet —
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

Enter on 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
Present when the button is disabled.
data-hidden
Present when the action does not apply to the active item.
data-shortcut
Enter on an enabled, visible Next or Submit.
data-status
The active item's status: unanswered, answered or skipped.
data-visible
Present when the action applies to the active item.

Submit

Submits the form from the last item. Renders a <button> element.

children Snippet —
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

Enter on 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
Present when the button is disabled.
data-hidden
Present when the action does not apply to the active item.
data-shortcut
Enter on an enabled, visible Next or Submit.
data-status
The active item's status: unanswered, answered or skipped.
data-visible
Present when the action applies to the active item.