Questionnaire
Un formulaire pas à pas qui passe d'une question à l'autre avec un sens de direction, montre une vraie progression et répond au clavier.
pnpm dlx shadcn@latest add https://hextaui.com/r/questionnaire.jsonAjoute le composant, les tokens de thème HextaUI et les composants HextaUI dont il dépend.
Ajoutez les tokens de thème à votre CSS global, si ce n’est pas déjà fait.
Installez les dépendances.
pnpm add @shadcn/react @base-ui/react @tabler/icons-react class-variance-authority cnCopiez et collez le code suivant dans votre projet.
components/ui/questionnaire.tsx components/ui/button.tsx components/ui/input.tsx components/ui/kbd.tsx components/ui/number-flow.tsx lib/motion.ts Mettez à jour les chemins d’import selon la configuration de votre projet.
Les réponses sont envoyées comme un formulaire classique, indexées par le name de chaque élément. Les questions se déplacent dans le sens où vous allez, la carte s'adapte en douceur à la hauteur de chaque question, et la progression ne se remplit que pour les questions répondues ou passées.
Transition lift et barre
transition="lift" déplace les questions vers le haut et le bas comme une pile. variant="bar" sur la progression affiche une seule barre continue.
Avance automatique
Avec autoAdvance, choisir une réponse unique passe à la suite après une courte pause, ce qui permet de répondre avec 1–5 seulement. Modifier une réponse précédente ne fait jamais avancer, et la dernière question ne s'envoie jamais toute seule.
Questions conditionnelles
Désactivez un élément pour l'écarter. Il disparaît de la progression et du parcours tant qu'il ne s'applique pas.
De droite à gauche
Le glissement suit le sens de lecture.
| Touche | Action |
|---|---|
| ↑↓ | Se déplace entre les réponses, y compris le champ de texte. Se déplacer ne sélectionne pas. |
| Space | Choisit la réponse qui a le focus, ou la bascule en choix multiple. |
| Enter | Continue. Sur une réponse unique non choisie, la sélectionne d'abord. Envoie à la dernière question. |
| ←→ | Question précédente ou suivante, inversées en droite à gauche. Suivant tremble quand une réponse est requise. Dans le champ de texte, elles déplacent le curseur. |
| HomeEnd | Première ou dernière réponse. |
| A1 | Choisit une réponse par sa touche quand shortcuts est défini. Les capuchons s'éclaircissent une fois que le questionnaire a le focus ; cliquez n'importe où dedans pour commencer. |
| Esc | Quitte le champ de texte pour que les raccourcis à lettre refonctionnent. |
| ⌘Enter | Envoie depuis n'importe où. |
- Chaque
QuestionnaireItemest un<fieldset>dont le titre est son<legend>. Les questions inactives sont masquées et inertes, y compris celle qui sort en animation. - La progression est une
progressbarqui annonce « Question 2 sur 5 » ; les segments et le nombre qui tourne sont décoratifs. - Les erreurs utilisent
role="alert"et les réponses invalides reçoiventaria-invalid. - Avec la réduction des animations, les questions changent instantanément et rien ne tremble.
| Prop | Type | Par défaut |
|---|---|---|
transition | "slide" | "lift" | "slide" |
autoAdvancePasse à la suite 350ms après le premier choix d'une réponse unique. | boolean | false |
shortcutsAjoute un raccourci clavier à chaque réponse. | "letters" | "numbers" | – |
item | string | – |
defaultItem | string | – |
onItemChange | (item: string) => void | – |
| Attribut | Description |
|---|---|
data-slot="questionnaire" | Le formulaire, avec data-transition. |
data-current / data-total | La position actuelle et le nombre de questions. |
data-first / data-last | Présent sur la première ou la dernière question. |
| Prop | Type | Par défaut |
|---|---|---|
variant | "segments" | "bar" | "segments" |
| Attribut | Description |
|---|---|
data-slot="questionnaire-progress-segment" | Un par question, avec data-status, data-active et data-invalid. |
| Prop | Type | Par défaut |
|---|---|---|
nameLe nom du champ de formulaire. | string | – |
required | boolean | false |
multipleDes cases à cocher au lieu de boutons radio. | boolean | false |
disabledÉcarte la question du parcours. | boolean | false |
onStatusChange | (status) => void | – |
| Attribut | Description |
|---|---|
data-status | "unanswered", "answered" ou "skipped". |
data-active | La question courante. |
data-invalid | Demande une réponse. |
data-leaving | La question qui sort en animation. |
| Prop | Type | Par défaut |
|---|---|---|
value | string | – |
defaultChecked | boolean | – |
disabled | boolean | false |
render | ReactElement | (props, state) => ReactElement | <label> |
| Attribut | Description |
|---|---|
data-checked / data-unchecked | Indique si la réponse est choisie. |
data-type | "radio" ou "checkbox". |
data-shortcut | La touche de la réponse. |
Une réponse en texte libre qui se place avec les choix. Saisir du texte efface le choix sélectionné. Donnez-lui un label ou un aria-label.
| Prop | Type | Par défaut |
|---|---|---|
variant | Button variant | "ghost", or "default" for Next and Submit |
size | Button size | "default" |
QuestionnaireNext et QuestionnaireSubmit partagent un emplacement : à la dernière question, Suivant est remplacé par Envoyer sans que rien ne bouge.
- ButtonDes boutons dans toutes les variantes et tailles, avec un flux de chargement, de succès et d’erreur intégré qui évite le spinner pour les requêtes rapides.
- InputUn champ de saisie texte en trois tailles, avec états invalide et lecture seule, style de validation natif et police tactile de 16px pour que les téléphones ne zooment jamais.
- KbdDes keycaps pour les raccourcis qui affichent les bons symboles sur chaque plateforme, se lisent correctement à voix haute et s’enfoncent comme de vraies touches.
- MotionLes courbes d’easing, les durées et la vérification de réduction des animations utilisées par chaque composant, ainsi que des hooks pour les morphs de taille et les surlignages glissants.
- Number flowDes nombres animés où seuls les chiffres modifiés tournent, avec n’importe quel format Intl et n’importe quelle locale.
- CalendarUne grille de dates pour la sélection simple, de plage et multiple, avec des mois qui défilent, des aperçus de plage et des jours à taille tactile.
Utilisé dans les blocks
Des blocks qui s’appuient sur Questionnaire.