Questionnaire
Ein schrittweises Formular, das mit Richtungsgefühl zwischen Fragen wechselt, echten Fortschritt zeigt und per Tastatur beantwortet wird.
pnpm dlx shadcn@latest add https://hextaui.com/r/questionnaire.jsonFügt die Komponente, die HextaUI-Theme-Tokens und alle HextaUI-Komponenten hinzu, von denen sie abhängt.
Füge die Theme-Tokens zu deinem globalen CSS hinzu, falls du das noch nicht getan hast.
Installiere die Abhängigkeiten.
pnpm add @shadcn/react @base-ui/react @tabler/icons-react class-variance-authority cnKopiere den folgenden Code und füge ihn in dein Projekt ein.
components/ui/questionnaire.tsx components/ui/button.tsx components/ui/input.tsx components/ui/kbd.tsx components/ui/number-flow.tsx lib/motion.ts Passe die Importpfade an dein Projekt-Setup an.
Antworten werden wie ein normales Formular abgeschickt, geordnet nach dem name jedes Items. Fragen bewegen sich in die Richtung, in die du gehst, die Karte passt sich sanft der Höhe jeder Frage an, und der Fortschritt füllt sich nur für beantwortete oder übersprungene Fragen.
Lift-Übergang und Leiste
transition="lift" bewegt Fragen wie einen Stapel auf und ab. variant="bar" am Progress zeigt eine durchgehende Leiste.
Automatisch weiter
Mit autoAdvance geht es nach einer kurzen Pause weiter, wenn eine Einzelantwort gewählt wird, sodass du allein mit 1–5 antworten kannst. Das Ändern einer früheren Antwort springt nie voraus, und die letzte Frage sendet nie von selbst ab.
Bedingte Fragen
Deaktiviere ein Item, um es auszulassen. Es fällt aus Fortschritt und Ablauf heraus, bis es zutrifft.
Rechts nach links
Das Gleiten folgt der Leserichtung.
| Taste | Aktion |
|---|---|
| ↑↓ | Wechselt zwischen den Antworten, auch dem Textfeld. Das Wechseln wählt nicht aus. |
| Space | Wählt die fokussierte Antwort oder schaltet sie bei Mehrfachauswahl um. |
| Enter | Geht weiter. Bei einer nicht gewählten Einzelantwort wählt es sie zuerst. Sendet bei der letzten Frage ab. |
| ←→ | Vorherige oder nächste Frage, in rechts-nach-links gespiegelt. Next wackelt, wenn eine Antwort nötig ist. Im Textfeld bewegen sie den Cursor. |
| HomeEnd | Erste oder letzte Antwort. |
| A1 | Wählt eine Antwort über ihre Taste, wenn shortcuts gesetzt ist. Tastenkappen leuchten auf, sobald der Questionnaire den Fokus hat; klicke irgendwo hinein, um zu beginnen. |
| Esc | Verlässt das Textfeld, sodass Buchstaben-Kürzel wieder funktionieren. |
| ⌘Enter | Sendet von überall ab. |
- Jedes
QuestionnaireItemist ein<fieldset>, dessen Titel sein<legend>ist. Inaktive Fragen sind ausgeblendet und inert, auch die, die gerade ausblendet. - Der Fortschritt ist eine
progressbar, die „Question 2 of 5“ ansagt; die Segmente und die drehende Zahl sind Dekoration. - Fehler verwenden
role="alert", und die ungültigen Antworten erhaltenaria-invalid. - Bei reduzierter Bewegung wechseln Fragen sofort, und nichts wackelt.
| Prop | Typ | Standard |
|---|---|---|
transition | "slide" | "lift" | "slide" |
autoAdvanceGeht 350ms weiter, nachdem zum ersten Mal eine Einzelantwort gewählt wurde. | boolean | false |
shortcutsFügt jeder Antwort ein Tastenkürzel hinzu. | "letters" | "numbers" | – |
item | string | – |
defaultItem | string | – |
onItemChange | (item: string) => void | – |
| Attribut | Beschreibung |
|---|---|
data-slot="questionnaire" | Das Formular, mit data-transition. |
data-current / data-total | Die aktuelle Position und die Anzahl der Fragen. |
data-first / data-last | Vorhanden bei der ersten oder letzten Frage. |
| Prop | Typ | Standard |
|---|---|---|
variant | "segments" | "bar" | "segments" |
| Attribut | Beschreibung |
|---|---|
data-slot="questionnaire-progress-segment" | Eines pro Frage, mit data-status, data-active und data-invalid. |
| Prop | Typ | Standard |
|---|---|---|
nameDer Name des Formularfelds. | string | – |
required | boolean | false |
multipleCheckboxen statt Radios. | boolean | false |
disabledLässt die Frage im Ablauf aus. | boolean | false |
onStatusChange | (status) => void | – |
| Attribut | Beschreibung |
|---|---|
data-status | "unanswered", "answered" oder "skipped". |
data-active | Die aktuelle Frage. |
data-invalid | Braucht eine Antwort. |
data-leaving | Die Frage, die gerade ausblendet. |
| Prop | Typ | Standard |
|---|---|---|
value | string | – |
defaultChecked | boolean | – |
disabled | boolean | false |
render | ReactElement | (props, state) => ReactElement | <label> |
| Attribut | Beschreibung |
|---|---|
data-checked / data-unchecked | Ob die Antwort gewählt ist. |
data-type | "radio" oder "checkbox". |
data-shortcut | Die Taste der Antwort. |
Eine Freitext-Antwort neben den Auswahlmöglichkeiten. Tippen hebt die gewählte Auswahl auf. Gib ihr ein Label oder aria-label.
| Prop | Typ | Standard |
|---|---|---|
variant | Button variant | "ghost", or "default" for Next and Submit |
size | Button size | "default" |
QuestionnaireNext und QuestionnaireSubmit teilen sich einen Slot, sodass bei der letzten Frage Next gegen Submit getauscht wird, ohne dass sich etwas verschiebt.
- ButtonButtons in allen Varianten und Größen, mit eingebautem Lade-, Erfolgs- und Fehlerablauf, der den Spinner bei schnellen Anfragen überspringt.
- InputEin Texteingabefeld mit drei Größen, ungültigen und schreibgeschützten Zuständen, nativem Validierungsstyling und einer 16-px-Schrift für Touch, damit Smartphones nie hineinzoomen.
- KbdTastenkappen für Tastenkürzel, die auf jeder Plattform die richtigen Symbole zeigen, korrekt vorgelesen werden und sich wie echte Tasten eindrücken.
- MotionDie Easing-Kurven, Dauern und der Reduced-Motion-Check, mit denen jede Komponente animiert, plus Hooks für Größen-Morphs und gleitende Hervorhebungen.
- Number flowAnimierte Zahlen, bei denen sich nur die geänderten Ziffern drehen, mit beliebigem Intl-Format und Locale.
- CalendarEin Datumsraster für Einzel-, Bereichs- und Mehrfachauswahl, mit gleitenden Monaten, Bereichsvorschau und Tagen in Touch-Größe.
In Blocks verwendet
Blocks, die auf Questionnaire aufbauen.