Wizard
<co-form-wizard> envuelve <co-form> para soportar multi-page forms con stepper navegable, validación por página, conditional logic a nivel page, y scoring opcional para modo quiz.
Schema paged
Sección titulada «Schema paged»Cuando un schema tiene pages: [...], el preview enruta automáticamente al wizard (en lugar del <co-form> flat).
{ "title": "Registro DevConf 2026", "description": "Únete a la conferencia", "mode": "form", "pages": [ { "name": "personal", "title": "Datos personales", "description": "Solo lo esencial", "fields": { "full_name": { "type": "String", "required": true, "label": "Nombre" }, "email": { "type": "String", "required": true, "format": "email" } } }, { "name": "preferences", "title": "Preferencias", "visibleIf": "{full_name} != ''", "fields": { "tracks": { "type": "String", "enum": ["AI/ML", "Frontend"], "multiple": true } } } ]}Características
Sección titulada «Características»Stepper navegable
Sección titulada «Stepper navegable»Cada page aparece como un step en el header. Click en un step:
- Hacia atrás → salta directo (ya visitaste esa page).
- Hacia adelante → valida la page actual y avanza una a la vez (no salta sin validar intermedias).
Los steps marcan is-active y is-done con colores del accent.
visibleIf a nivel page
Sección titulada «visibleIf a nivel page»Una page entera se oculta si su visibleIf evalúa a falso contra los valores acumulados:
{ "name": "advanced", "title": "Configuración avanzada", "visibleIf": "{role} == 'admin'", "fields": {/* ... */}}Sintaxis igual que en fields — operadores ==, !=, >, <, >=, <=, contains, &&, ||.
Validación por página
Sección titulada «Validación por página»Siguiente solo avanza si la page actual valida (touched + isValid). Si hay errores, los muestra y queda en la page. AJV se ejecuta scoped a los fields de la page.
Page header smart
Sección titulada «Page header smart»El page header (PAGE N pill + título + description) se muestra solo cuando aporta info:
- Multi-page → siempre se muestra (orientación al usuario).
- Single-page con título default “Page N” y sin description → se oculta entero (el form title ya da contexto).
- Single-page con título custom o description → muestra solo lo customizado.
Override explícito por page:
{ "name": "p1", "title": "Page 1", "hideTitle": true, // ocultar el h2 "hideDescription": true // ocultar el párrafo}Quiz mode
Sección titulada «Quiz mode»mode: "quiz" activa el sistema de scoring. Cada field puede declarar quiz: { correctAnswer, points }:
{ "mode": "quiz", "pages": [{ "name": "p1", "title": "Vue 3 quiz", "fields": { "q1": { "type": "String", "enum": ["ref()", "reactive()", "computed()"], "label": "¿Cuál crea un proxy reactivo?", "quiz": { "correctAnswer": "reactive()", "points": 10 } }, "q2": { "type": "Boolean", "label": "Los refs auto-unwrappean en template", "quiz": { "correctAnswer": true, "points": 5 } } } }], "scoring": { "showScore": true, "passingScore": 70, "feedbackRules": [ { "expression": "{_score} >= 80", "message": "Excelente!" }, { "expression": "{_score} < 50", "message": "Repasar la doc" } ] }}Al hacer Submit, el wizard:
- Calcula el score sumando puntos de respuestas correctas vs total.
- Compara con
passingScore→passed: boolean. - Evalúa cada
feedbackRules.expression(con{_score}disponible como % calculado). - Renderiza un panel de resultados con score, pass/fail badge y feedback messages.
- Emite
coSubmitevent con{ values, score: ScoreResult }.
Comparación de respuestas
Sección titulada «Comparación de respuestas»- Escalares: loose equality (
==), así"5" == 5estrue. - Arrays (multi-select): order-insensitive —
["a","b"]matchea["b","a"].
Estructura visual
Sección titulada «Estructura visual»┌─ co-form-wizard (data-theme, data-density, ...) ─────────┐│ ││ ┌─ Title block card ────────────────────────────────┐ ││ │ Form title (h1) │ ││ │ Form description │ ││ └───────────────────────────────────────────────────┘ ││ ││ Stepper: ① Page 1 ② Page 2 ③ Page 3 ││ ││ ┌─ Page card (active) ──────────────────────────────┐ ││ │ ┌─ Page head ─────────────────────────────────┐ │ ││ │ │ PAGE 2 pill │ │ ││ │ │ Page title (h2) │ │ ││ │ │ Page description │ │ ││ │ └─────────────────────────────────────────────┘ │ ││ │ │ ││ │ <co-form> con los fields de esta page │ ││ │ │ ││ │ ┌─ Nav ────────────────────────────────────────┐ │ ││ │ │ [Anterior] [Siguiente] │ │ ││ │ └─────────────────────────────────────────────┘ │ ││ └───────────────────────────────────────────────────┘ │└──────────────────────────────────────────────────────────┘Embebido directo
Sección titulada «Embebido directo»<co-form-wizard schema='{ "title": "...", "pages": [...] }' theme='{ "colorScheme": "dark", "accent": "verde" }' layout="grid" columns="1"></co-form-wizard>
<script>const wizard = document.querySelector('co-form-wizard');wizard.addEventListener('coSubmit', (ev) => { console.log('Values:', ev.detail.values); console.log('Score:', ev.detail.score); // solo en mode: quiz});wizard.addEventListener('coPageChange', (ev) => { console.log('Now on page', ev.detail.index);});</script>| Prop | Tipo | Default | Descripción |
|---|---|---|---|
schema | string (JSON) | required | Paged schema con pages[]. |
theme | string (JSON) | — | Theme spec — ver Theme. |
initial-values | string (JSON) | '{}' | Pre-fill global, distribuye automáticamente por página. |
locale | 'en' | 'es' | 'pt' | 'es' | Idioma de errores AJV. |
layout | 'grid' | 'stack' | 'grid' | Layout pasado al <co-form> interno. |
columns | 1 | 2 | 3 | 4 | 1 | Columnas del grid. |
Eventos
Sección titulada «Eventos»| Event | Payload | Cuándo |
|---|---|---|
coSubmit | { values, score? } | Al completar el último step. score solo en mode: quiz. |
coPageChange | { index, page } | Cambio de page activa (manual o via stepper). |