Form schema

Switch

Learn how the switch element is used in the schema.


Usage

The switch element is used to define multiple conditions.

To understand how it is used let's look at this example.

import type { Schema, Switch, Form, Return } from "@formity/react";

import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";

import {
  Step,
  Layout,
  TextField,
  Listbox,
  NextButton,
  BackButton,
} from "./components";

import { MultiStep } from "./multi-step";

export type Values = [
  Form<{ interested: string }>,
  Switch<{
    branches: [
      [Form<{ whyYes: string }>, Return<{ interested: "yes"; whyYes: string }>],
      [Form<{ whyNot: string }>, Return<{ interested: "no"; whyNot: string }>],
      [
        Form<{ whyMaybe: string }>,
        Return<{ interested: "maybe"; whyMaybe: string }>,
      ],
    ];
    default: [
      Form<{ whyNotSure: string }>,
      Return<{ interested: "notSure"; whyNotSure: string }>,
    ];
  }>,
];

export const schema: Schema<Values> = [
  {
    form: {
      values: () => ({
        interested: ["yes", []],
      }),
      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: "yes",
                      label: "Yes, that sounds good.",
                    },
                    {
                      value: "no",
                      label: "No, it is not for me.",
                    },
                    {
                      value: "maybe",
                      label: "Maybe in another time.",
                    },
                    {
                      value: "notSure",
                      label: "I am not sure.",
                    },
                  ]}
                />,
              ]}
              button={<NextButton>Next</NextButton>}
            />
          </Step>
        </MultiStep>
      ),
    },
  },
  {
    switch: {
      branches: [
        {
          case: ({ interested }) => interested === "yes",
          then: [
            {
              form: {
                values: () => ({
                  whyYes: ["", []],
                }),
                render: ({ values, onNext, onBack }) => (
                  <MultiStep onNext={onNext} onBack={onBack}>
                    <Step
                      key="whyYes"
                      defaultValues={values}
                      resolver={zodResolver(
                        z.object({
                          whyYes: z.string(),
                        }),
                      )}
                    >
                      <Layout
                        heading="Why are you interested?"
                        description="We would like to know why you are interested"
                        fields={[
                          <TextField key="whyYes" name="whyYes" label="Why?" />,
                        ]}
                        button={<NextButton>Next</NextButton>}
                        back={<BackButton />}
                      />
                    </Step>
                  </MultiStep>
                ),
              },
            },
            {
              return: ({ whyYes }) => ({
                interested: "yes",
                whyYes,
              }),
            },
          ],
        },
        {
          case: ({ interested }) => interested === "no",
          then: [
            {
              form: {
                values: () => ({
                  whyNot: ["", []],
                }),
                render: ({ values, onNext, onBack }) => (
                  <MultiStep onNext={onNext} onBack={onBack}>
                    <Step
                      key="whyNot"
                      defaultValues={values}
                      resolver={zodResolver(
                        z.object({
                          whyNot: z.string(),
                        }),
                      )}
                    >
                      <Layout
                        heading="Why are you not interested?"
                        description="We would like to know why you are not interested"
                        fields={[
                          <TextField key="whyNot" name="whyNot" label="Why?" />,
                        ]}
                        button={<NextButton>Next</NextButton>}
                        back={<BackButton />}
                      />
                    </Step>
                  </MultiStep>
                ),
              },
            },
            {
              return: ({ whyNot }) => ({
                interested: "no",
                whyNot,
              }),
            },
          ],
        },
        {
          case: ({ interested }) => interested === "maybe",
          then: [
            {
              form: {
                values: () => ({
                  whyMaybe: ["", []],
                }),
                render: ({ values, onNext, onBack }) => (
                  <MultiStep onNext={onNext} onBack={onBack}>
                    <Step
                      key="whyMaybe"
                      defaultValues={values}
                      resolver={zodResolver(
                        z.object({
                          whyMaybe: z.string(),
                        }),
                      )}
                    >
                      <Layout
                        heading="Why are you maybe interested?"
                        description="We would like to know why you are maybe interested"
                        fields={[
                          <TextField
                            key="whyMaybe"
                            name="whyMaybe"
                            label="Why?"
                          />,
                        ]}
                        button={<NextButton>Next</NextButton>}
                        back={<BackButton />}
                      />
                    </Step>
                  </MultiStep>
                ),
              },
            },
            {
              return: ({ whyMaybe }) => ({
                interested: "maybe",
                whyMaybe,
              }),
            },
          ],
        },
      ],
      default: [
        {
          form: {
            values: () => ({
              whyNotSure: ["", []],
            }),
            render: ({ values, onNext, onBack }) => (
              <MultiStep onNext={onNext} onBack={onBack}>
                <Step
                  key="whyNotSure"
                  defaultValues={values}
                  resolver={zodResolver(
                    z.object({
                      whyNotSure: z.string(),
                    }),
                  )}
                >
                  <Layout
                    heading="Why are you not sure?"
                    description="We would like to know why you are not sure"
                    fields={[
                      <TextField
                        key="whyNotSure"
                        name="whyNotSure"
                        label="Why?"
                      />,
                    ]}
                    button={<NextButton>Next</NextButton>}
                    back={<BackButton />}
                  />
                </Step>
              </MultiStep>
            ),
          },
        },
        {
          return: ({ whyNotSure }) => ({
            interested: "notSure",
            whyNotSure,
          }),
        },
      ],
    },
  },
];

We need to use the Switch type with the corresponding types.

export type Values = [
  // ...
  Switch<{
    branches: [
      [Form<{ whyYes: string }>, Return<{ interested: "yes"; whyYes: string }>],
      [Form<{ whyNot: string }>, Return<{ interested: "no"; whyNot: string }>],
      [
        Form<{ whyMaybe: string }>,
        Return<{ interested: "maybe"; whyMaybe: string }>,
      ],
    ];
    default: [
      Form<{ whyNotSure: string }>,
      Return<{ interested: "notSure"; whyNotSure: string }>,
    ];
  }>,
];

Then, in the schema we need to create an object with the following structure.

export const schema: Schema<Values> = [
  // ...
  {
    switch: {
      branches: [
        {
          case: ({ interested }) => interested === "yes",
          then: [
            {
              form: {
                values: () => ({
                  whyYes: ["", []],
                }),
                render: ({ values, onNext, onBack }) => (
                  <MultiStep onNext={onNext} onBack={onBack}>
                    <Step
                      key="whyYes"
                      defaultValues={values}
                      resolver={zodResolver(
                        z.object({
                          whyYes: z.string(),
                        }),
                      )}
                    >
                      <Layout
                        heading="Why are you interested?"
                        description="We would like to know why you are interested"
                        fields={[
                          <TextField key="whyYes" name="whyYes" label="Why?" />,
                        ]}
                        button={<NextButton>Next</NextButton>}
                        back={<BackButton />}
                      />
                    </Step>
                  </MultiStep>
                ),
              },
            },
            {
              return: ({ whyYes }) => ({
                interested: "yes",
                whyYes,
              }),
            },
          ],
        },
        {
          case: ({ interested }) => interested === "no",
          then: [
            {
              form: {
                values: () => ({
                  whyNot: ["", []],
                }),
                render: ({ values, onNext, onBack }) => (
                  <MultiStep onNext={onNext} onBack={onBack}>
                    <Step
                      key="whyNot"
                      defaultValues={values}
                      resolver={zodResolver(
                        z.object({
                          whyNot: z.string(),
                        }),
                      )}
                    >
                      <Layout
                        heading="Why are you not interested?"
                        description="We would like to know why you are not interested"
                        fields={[
                          <TextField key="whyNot" name="whyNot" label="Why?" />,
                        ]}
                        button={<NextButton>Next</NextButton>}
                        back={<BackButton />}
                      />
                    </Step>
                  </MultiStep>
                ),
              },
            },
            {
              return: ({ whyNot }) => ({
                interested: "no",
                whyNot,
              }),
            },
          ],
        },
        {
          case: ({ interested }) => interested === "maybe",
          then: [
            {
              form: {
                values: () => ({
                  whyMaybe: ["", []],
                }),
                render: ({ values, onNext, onBack }) => (
                  <MultiStep onNext={onNext} onBack={onBack}>
                    <Step
                      key="whyMaybe"
                      defaultValues={values}
                      resolver={zodResolver(
                        z.object({
                          whyMaybe: z.string(),
                        }),
                      )}
                    >
                      <Layout
                        heading="Why are you maybe interested?"
                        description="We would like to know why you are maybe interested"
                        fields={[
                          <TextField
                            key="whyMaybe"
                            name="whyMaybe"
                            label="Why?"
                          />,
                        ]}
                        button={<NextButton>Next</NextButton>}
                        back={<BackButton />}
                      />
                    </Step>
                  </MultiStep>
                ),
              },
            },
            {
              return: ({ whyMaybe }) => ({
                interested: "maybe",
                whyMaybe,
              }),
            },
          ],
        },
      ],
      default: [
        {
          form: {
            values: () => ({
              whyNotSure: ["", []],
            }),
            render: ({ values, onNext, onBack }) => (
              <MultiStep onNext={onNext} onBack={onBack}>
                <Step
                  key="whyNotSure"
                  defaultValues={values}
                  resolver={zodResolver(
                    z.object({
                      whyNotSure: z.string(),
                    }),
                  )}
                >
                  <Layout
                    heading="Why are you not sure?"
                    description="We would like to know why you are not sure"
                    fields={[
                      <TextField
                        key="whyNotSure"
                        name="whyNotSure"
                        label="Why?"
                      />,
                    ]}
                    button={<NextButton>Next</NextButton>}
                    back={<BackButton />}
                  />
                </Step>
              </MultiStep>
            ),
          },
        },
        {
          return: ({ whyNotSure }) => ({
            interested: "notSure",
            whyNotSure,
          }),
        },
      ],
    },
  },
];

The branches property is an array of objects with two properties. The case property is a function that returns a boolean value. If it is true, the elements in then are used.

The first condition that evaluates to true is the one that is used. If no case evaluates to true, the elements in default are used.