Basic concepts
Schema
Learn what the schema is about and how it can be used to define the forms.
Schema
The schema is used to define the structure and behavior of the multi-step form. It is an array of different elements, and the existing ones are as follows:
- Form: Defines a step in the form.
- Yield: Defines what values the multi-step form yields.
- Return: Defines what values the multi-step form returns.
- Variables: Defines variables.
- Condition: Defines a condition.
- Loop: Defines a loop.
- Switch: Defines a switch.
By combining these elements, we can create advanced multi-step forms with complex logic. Here's an example to illustrate how these elements work together.
import type { Schema, Form, Return, Cond } from "@formity/react";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import {
Step,
Layout,
Row,
TextField,
NumberField,
YesNo,
MultiSelect,
Listbox,
NextButton,
BackButton,
} from "./components";
import { MultiStep } from "./multi-step";
export type Values = [
Form<{ name: string; surname: string; age: number }>,
Form<{ softwareDeveloper: boolean }>,
Cond<{
then: [
Form<{ languages: string[] }>,
Return<{
name: string;
surname: string;
age: number;
softwareDeveloper: true;
languages: string[];
}>,
];
else: [
Form<{ interested: string }>,
Return<{
name: string;
surname: string;
age: number;
softwareDeveloper: false;
interested: string;
}>,
];
}>,
];
export const schema: Schema<Values> = [
{
form: {
values: () => ({
name: ["", []],
surname: ["", []],
age: [20, []],
}),
render: ({ values, onNext, onBack }) => (
<MultiStep onNext={onNext} onBack={onBack}>
<Step
key="main"
defaultValues={values}
resolver={zodResolver(
z.object({
name: z
.string()
.min(1, { message: "Required" })
.max(20, { message: "Must be at most 20 characters" }),
surname: z
.string()
.min(1, { message: "Required" })
.max(20, { message: "Must be at most 20 characters" }),
age: z
.number()
.min(18, { message: "Minimum of 18 years old" })
.max(99, { message: "Maximum of 99 years old" }),
}),
)}
>
<Layout
heading="Tell us about yourself"
description="We would want to know about you"
fields={[
<Row
key="nameSurname"
items={[
<TextField key="name" name="name" label="Name" />,
<TextField key="surname" name="surname" label="Surname" />,
]}
/>,
<NumberField key="age" name="age" label="Age" />,
]}
button={<NextButton>Next</NextButton>}
/>
</Step>
</MultiStep>
),
},
},
{
form: {
values: () => ({
softwareDeveloper: [true, []],
}),
render: ({ values, onNext, onBack }) => (
<MultiStep onNext={onNext} onBack={onBack}>
<Step
key="softwareDeveloper"
defaultValues={values}
resolver={zodResolver(
z.object({
softwareDeveloper: z.boolean(),
}),
)}
>
<Layout
heading="Are you a software developer?"
description="We would like to know if you are a software developer"
fields={[
<YesNo
key="softwareDeveloper"
name="softwareDeveloper"
label="Software Developer"
/>,
]}
button={<NextButton>Next</NextButton>}
back={<BackButton />}
/>
</Step>
</MultiStep>
),
},
},
{
cond: {
if: ({ softwareDeveloper }) => softwareDeveloper,
then: [
{
form: {
values: () => ({
languages: [[], []],
}),
render: ({ values, onNext, onBack }) => (
<MultiStep onNext={onNext} onBack={onBack}>
<Step
key="languages"
defaultValues={values}
resolver={zodResolver(
z.object({
languages: z.array(z.string()),
}),
)}
>
<Layout
heading="What are your favourite programming languages?"
description="We would like to know which of the following programming languages you like the most"
fields={[
<MultiSelect
key="languages"
name="languages"
label="Languages"
options={[
{ value: "javascript", label: "JavaScript" },
{ value: "python", label: "Python" },
{ value: "go", label: "Go" },
]}
direction="y"
/>,
]}
button={<NextButton>Next</NextButton>}
back={<BackButton />}
/>
</Step>
</MultiStep>
),
},
},
{
return: ({ name, surname, age, languages }) => ({
name,
surname,
age,
softwareDeveloper: true,
languages,
}),
},
],
else: [
{
form: {
values: () => ({
interested: ["maybe", []],
}),
render: ({ values, onNext, onBack }) => (
<MultiStep onNext={onNext} onBack={onBack}>
<Step
key="interested"
defaultValues={values}
resolver={zodResolver(
z.object({
interested: z.string(),
}),
)}
>
<Layout
heading="Would you be interested in learning how to code?"
description="Having coding skills can be very beneficial"
fields={[
<Listbox
key="interested"
name="interested"
label="Interested"
options={[
{
value: "maybe",
label: "Maybe in another time.",
},
{
value: "yes",
label: "Yes, that sounds good.",
},
{
value: "no",
label: "No, it is not for me.",
},
]}
/>,
]}
button={<NextButton>Next</NextButton>}
back={<BackButton />}
/>
</Step>
</MultiStep>
),
},
},
{
return: ({ name, surname, age, interested }) => ({
name,
surname,
age,
softwareDeveloper: false,
interested,
}),
},
],
},
},
];
The schema is of type Schema
, and in this particular example, it contains form, return and condition elements.
Moreover, to ensure complete type safety, this type accepts a Values
type that defines the values handled at each step of the multi-step form.
For a deeper understanding of each element, detailed explanations are available in their respective sections.