Cuestionario
Un formulario paso a paso que se mueve entre preguntas con sensación de dirección, muestra el progreso real y responde desde el teclado.
pnpm dlx shadcn@latest add https://hextaui.com/r/questionnaire.jsonAñade el componente, los tokens del tema de HextaUI y los componentes de HextaUI de los que depende.
Añade los tokens del tema a tu CSS global, si aún no lo has hecho.
Instala las dependencias.
pnpm add @shadcn/react @base-ui/react @tabler/icons-react class-variance-authority cnCopia y pega el siguiente código en tu proyecto.
components/ui/questionnaire.tsx components/ui/button.tsx components/ui/input.tsx components/ui/kbd.tsx components/ui/number-flow.tsx lib/motion.ts Actualiza las rutas de importación para que coincidan con la configuración de tu proyecto.
Las respuestas se envían como un formulario normal, identificadas por el name de cada elemento. Las preguntas se mueven hacia la dirección en la que vas, la tarjeta se ajusta suavemente a la altura de cada pregunta, y el progreso solo se rellena con las preguntas respondidas u omitidas.
Transición lift y barra
transition="lift" mueve las preguntas hacia arriba y abajo como una pila. variant="bar" en el progreso muestra una barra continua.
Avance automático
Con autoAdvance, elegir una respuesta única avanza tras una breve pausa, así que puedes responder solo con 1–5. Cambiar una respuesta anterior nunca salta hacia delante, y la última pregunta nunca se envía sola.
Preguntas condicionales
Deshabilita un elemento para dejarlo fuera. Desaparece del progreso y del flujo hasta que corresponda.
De derecha a izquierda
El deslizamiento sigue la dirección de lectura.
| Key | Acción |
|---|---|
| ↑↓ | Se mueve entre las respuestas, incluido el campo de texto. Moverse no elige. |
| Space | Elige la respuesta enfocada, o la alterna en opción múltiple. |
| Enter | Continúa. Si una respuesta única no está elegida, la elige primero. En la última pregunta, envía. |
| ←→ | Pregunta anterior o siguiente, invertidas en derecha a izquierda. Next vibra cuando falta una respuesta. Dentro del campo de texto mueven el cursor. |
| HomeEnd | Primera o última respuesta. |
| A1 | Elige una respuesta por su tecla cuando se define shortcuts. Las teclas se iluminan cuando el cuestionario tiene el foco; haz clic en cualquier punto para empezar. |
| Esc | Sale del campo de texto para que los atajos de letras vuelvan a funcionar. |
| ⌘Enter | Envía desde cualquier punto. |
- Cada
QuestionnaireItemes un<fieldset>cuyo título es su<legend>. Las preguntas inactivas están ocultas e inertes, incluida la que se anima al salir. - El progreso es un
progressbarque anuncia “Pregunta 2 de 5”; los segmentos y el número giratorio son decorativos. - Los errores usan
role="alert"y las respuestas no válidas recibenaria-invalid. - Con movimiento reducido, las preguntas cambian al instante y nada vibra.
| Prop | Tipo | Predeterminado |
|---|---|---|
transition | "slide" | "lift" | "slide" |
autoAdvanceAvanza 350ms después de que se elija por primera vez una respuesta única. | boolean | false |
shortcutsAñade un atajo de teclado a cada respuesta. | "letters" | "numbers" | – |
item | string | – |
defaultItem | string | – |
onItemChange | (item: string) => void | – |
| Atributo | Descripción |
|---|---|
data-slot="questionnaire" | El formulario, con data-transition. |
data-current / data-total | La posición actual y el número de preguntas. |
data-first / data-last | Presente en la primera o la última pregunta. |
| Prop | Tipo | Predeterminado |
|---|---|---|
variant | "segments" | "bar" | "segments" |
| Atributo | Descripción |
|---|---|
data-slot="questionnaire-progress-segment" | Uno por pregunta, con data-status, data-active y data-invalid. |
| Prop | Tipo | Predeterminado |
|---|---|---|
nameEl nombre del campo del formulario. | string | – |
required | boolean | false |
multipleCheckboxes en lugar de radios. | boolean | false |
disabledDeja la pregunta fuera del flujo. | boolean | false |
onStatusChange | (status) => void | – |
| Atributo | Descripción |
|---|---|
data-status | "unanswered", "answered" o "skipped". |
data-active | La pregunta actual. |
data-invalid | Necesita una respuesta. |
data-leaving | La pregunta que se anima al salir. |
| Prop | Tipo | Predeterminado |
|---|---|---|
value | string | – |
defaultChecked | boolean | – |
disabled | boolean | false |
render | ReactElement | (props, state) => ReactElement | <label> |
| Atributo | Descripción |
|---|---|
data-checked / data-unchecked | Si la respuesta está elegida. |
data-type | "radio" o "checkbox". |
data-shortcut | La tecla de la respuesta. |
Una respuesta de texto libre que acompaña a las opciones. Al escribir se borra la opción elegida. Dale una etiqueta o aria-label.
| Prop | Tipo | Predeterminado |
|---|---|---|
variant | Button variant | "ghost", or "default" for Next and Submit |
size | Button size | "default" |
QuestionnaireNext y QuestionnaireSubmit comparten un hueco, así que en la última pregunta Next se cambia por Submit sin mover nada.
- ButtonBotones en todas las variantes y tamaños, con un flujo integrado de carga, éxito y error que omite el spinner en las peticiones rápidas.
- InputUn campo de texto con tres tamaños, estados inválido y de solo lectura, estilos de validación nativos y una fuente táctil de 16px para que los móviles nunca hagan zoom.
- KbdTeclas para atajos que muestran los símbolos correctos en cada plataforma, se leen en voz alta correctamente y se hunden como las teclas reales.
- MotionLas curvas de easing, duraciones y la comprobación de movimiento reducido con las que se anima cada componente, además de hooks para transformaciones de tamaño y resaltados deslizantes.
- Number flowNúmeros animados donde solo giran los dígitos que cambian, con cualquier formato Intl y configuración regional.
- CalendarUna cuadrícula de fechas para selección única, de rango y múltiple, con meses deslizantes, vistas previas de rango y días de tamaño táctil.
Usado en bloques
Bloques que se construyen sobre Questionnaire.