Multi-step forms
When a definition's layout has steps, <JsonFields> renders the current one, and jsonForm.steps moves between them. Below you will learn how to render a form with steps.
Rendering steps
jsonForm.steps is where the form is, and how to move. Render your own step indicator and buttons around <JsonFields>:
<script setup lang="ts">
import { Form } from '@formisch/vue'
import type { JsonForm } from '@whatsaaaa/form-builder-schema'
import { JsonFields, useJsonForm } from '@whatsaaaa/form-builder-vue'
import { components } from './all-fields'
import LayoutRow from './LayoutRow.vue'
const { definition } = defineProps<{ definition: JsonForm }>()
const jsonForm = useJsonForm(definition, {
components,
layoutComponents: { row: LayoutRow },
})
function save(output: unknown) {
console.log(output)
}
</script>
<template>
<Form :of="jsonForm.form" @submit="save">
<ol>
<li
v-for="(step, index) in jsonForm.steps.list"
:key="step.step.id ?? index"
:aria-current="index === jsonForm.steps.index ? 'step' : undefined"
>
{{ step.step.label }}
</li>
</ol>
<JsonFields :of="jsonForm" />
<button
v-if="!jsonForm.steps.isFirst"
type="button"
@click="jsonForm.steps.back()"
>
Back
</button>
<button
v-if="!jsonForm.steps.isLast"
type="button"
@click="jsonForm.steps.next()"
>
Next
</button>
<button v-else type="submit">Sign up</button>
</Form>
</template>import { Form } from '@formisch/react'
import type { JsonForm } from '@whatsaaaa/form-builder-schema'
import { JsonFields, useJsonForm } from '@whatsaaaa/form-builder-react'
import { components } from './all-fields'
import { layoutComponents } from './layout'
export function SignUpSteps({ definition }: { definition: JsonForm }) {
const jsonForm = useJsonForm(definition, { components, layoutComponents })
const { steps } = jsonForm
function save(output: unknown) {
console.log(output)
}
return (
<Form of={jsonForm.form} onSubmit={save}>
<ol>
{steps.list.map((step, index) => (
<li
key={step.step.id ?? index}
aria-current={index === steps.index ? 'step' : undefined}
>
{step.step.label}
</li>
))}
</ol>
<JsonFields of={jsonForm} />
{!steps.isFirst && (
<button type="button" onClick={steps.back}>
Back
</button>
)}
{steps.isLast ? (
<button type="submit">Sign up</button>
) : (
<button type="button" onClick={() => void steps.next()}>
Next
</button>
)}
</Form>
)
}In Vue, jsonForm.steps is reactive, so templates follow it. In React, the component re-renders when it changes.
Steps
| Member | What it is |
|---|---|
list | the steps on show, each with its step as written (id, label, description, ui) |
index, current | the step <JsonFields> renders: its index in list, and the step |
isFirst, isLast | whether it is the first or the last step on show |
next() | validates, and moves on when the step's fields have no errors. Resolves to whether it moved |
back() | moves back, without validating |
goTo(index) | moves back freely, or forward through each step on the way, stopping at the first with errors |
How steps validate
The form is one Formisch form, so Formisch validates all of it at once. The steps make that work:
- Next validates the whole form, and only the errors on the current step's fields keep the user there. It focuses the first one, in layout order.
- A step shows what the user left: the errors it had when they left it, and none the first time they get there, so errors on steps nobody saw yet stay out of sight.
- A step that failed Next revalidates as the user fixes it, on the
revalidateevent, like a form after a failed submit. - A submit before the last step is a Next, so Enter in a text input doesn't submit the form early. On the last step, Formisch submits as usual.
- A submit that fails because of an earlier step, like a form rule that reads fields of two steps, goes back to that step.
Hidden steps
With conditions, steps.list holds only the steps on show. A step that is hidden, or whose fields are all hidden, is left out, and Next and Back go past it. The step the user is on stays until they leave it.
A review page
<JsonFields> takes a step to render a given step instead of the current one, like on a review page that shows every step. A form without steps has one step, and nothing changes for it.