Form schemaSwitch

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, Form, Return, Switch } from "@formity/react";

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

import {
  FormStep,
  FormStepContent,
  FormStepHeading,
  FormStepInputs,
  FormStepRow,
} from "./components/form-step";

import { Select } from "./components/input/select";
import { TextInput } from "./components/input/text-input";
import { NextButton } from "./components/buttons/next-button";
import { BackButton } from "./components/buttons/back-button";

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 }>],
    ];
    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}>
          <FormStep
            key="interested"
            defaultValues={values}
            resolver={zodResolver(
              z.object({
                interested: z.string(),
              }),
            )}
          >
            <FormStepContent>
              <FormStepHeading>
                Are you interested in learning how to code?
              </FormStepHeading>
              <FormStepInputs>
                <Select
                  name="interested"
                  label="Interested"
                  options={[
                    { value: "yes", label: "Yes, I am interested." },
                    { value: "no", label: "No, it is not for me." },
                    { value: "maybe", label: "Maybe, I am not sure." },
                  ]}
                />
              </FormStepInputs>
              <NextButton>Next</NextButton>
            </FormStepContent>
          </FormStep>
        </MultiStep>
      ),
    },
  },
  {
    switch: {
      branches: [
        {
          case: ({ interested }) => interested === "yes",
          then: [
            {
              form: {
                values: () => ({
                  whyYes: ["", []],
                }),
                render: ({ values, onNext, onBack }) => (
                  <MultiStep onNext={onNext} onBack={onBack}>
                    <FormStep
                      key="whyYes"
                      defaultValues={values}
                      resolver={zodResolver(
                        z.object({
                          whyYes: z.string().min(1, "Required"),
                        }),
                      )}
                    >
                      <FormStepContent>
                        <FormStepHeading>
                          Why are you interested?
                        </FormStepHeading>
                        <FormStepInputs>
                          <TextInput
                            name="whyYes"
                            label="Why?"
                            placeholder="Write your answer here..."
                          />
                        </FormStepInputs>
                        <FormStepRow>
                          <BackButton>Back</BackButton>
                          <NextButton>Submit</NextButton>
                        </FormStepRow>
                      </FormStepContent>
                    </FormStep>
                  </MultiStep>
                ),
              },
            },
            {
              return: ({ whyYes }) => ({
                interested: "yes",
                whyYes,
              }),
            },
          ],
        },
        {
          case: ({ interested }) => interested === "no",
          then: [
            {
              form: {
                values: () => ({
                  whyNot: ["", []],
                }),
                render: ({ values, onNext, onBack }) => (
                  <MultiStep onNext={onNext} onBack={onBack}>
                    <FormStep
                      key="whyNot"
                      defaultValues={values}
                      resolver={zodResolver(
                        z.object({
                          whyNot: z.string().min(1, "Required"),
                        }),
                      )}
                    >
                      <FormStepContent>
                        <FormStepHeading>
                          Why are you not interested?
                        </FormStepHeading>
                        <FormStepInputs>
                          <TextInput
                            name="whyNot"
                            label="Why?"
                            placeholder="Write your answer here..."
                          />
                        </FormStepInputs>
                        <FormStepRow>
                          <BackButton>Back</BackButton>
                          <NextButton>Submit</NextButton>
                        </FormStepRow>
                      </FormStepContent>
                    </FormStep>
                  </MultiStep>
                ),
              },
            },
            {
              return: ({ whyNot }) => ({
                interested: "no",
                whyNot,
              }),
            },
          ],
        },
      ],
      default: [
        {
          form: {
            values: () => ({
              whyNotSure: ["", []],
            }),
            render: ({ values, onNext, onBack }) => (
              <MultiStep onNext={onNext} onBack={onBack}>
                <FormStep
                  key="whyNotSure"
                  defaultValues={values}
                  resolver={zodResolver(
                    z.object({
                      whyNotSure: z.string().min(1, "Required"),
                    }),
                  )}
                >
                  <FormStepContent>
                    <FormStepHeading>Why are you not sure?</FormStepHeading>
                    <FormStepInputs>
                      <TextInput
                        name="whyNotSure"
                        label="Why?"
                        placeholder="Write your answer here..."
                      />
                    </FormStepInputs>
                    <FormStepRow>
                      <BackButton>Back</BackButton>
                      <NextButton>Submit</NextButton>
                    </FormStepRow>
                  </FormStepContent>
                </FormStep>
              </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 }>],
    ];
    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}>
                    <FormStep
                      key="whyYes"
                      defaultValues={values}
                      resolver={zodResolver(
                        z.object({
                          whyYes: z.string().min(1, "Required"),
                        }),
                      )}
                    >
                      <FormStepContent>
                        <FormStepHeading>
                          Why are you interested?
                        </FormStepHeading>
                        <FormStepInputs>
                          <TextInput
                            name="whyYes"
                            label="Why?"
                            placeholder="Write your answer here..."
                          />
                        </FormStepInputs>
                        <FormStepRow>
                          <BackButton>Back</BackButton>
                          <NextButton>Submit</NextButton>
                        </FormStepRow>
                      </FormStepContent>
                    </FormStep>
                  </MultiStep>
                ),
              },
            },
            {
              return: ({ whyYes }) => ({
                interested: "yes",
                whyYes,
              }),
            },
          ],
        },
        {
          case: ({ interested }) => interested === "no",
          then: [
            {
              form: {
                values: () => ({
                  whyNot: ["", []],
                }),
                render: ({ values, onNext, onBack }) => (
                  <MultiStep onNext={onNext} onBack={onBack}>
                    <FormStep
                      key="whyNot"
                      defaultValues={values}
                      resolver={zodResolver(
                        z.object({
                          whyNot: z.string().min(1, "Required"),
                        }),
                      )}
                    >
                      <FormStepContent>
                        <FormStepHeading>
                          Why are you not interested?
                        </FormStepHeading>
                        <FormStepInputs>
                          <TextInput
                            name="whyNot"
                            label="Why?"
                            placeholder="Write your answer here..."
                          />
                        </FormStepInputs>
                        <FormStepRow>
                          <BackButton>Back</BackButton>
                          <NextButton>Submit</NextButton>
                        </FormStepRow>
                      </FormStepContent>
                    </FormStep>
                  </MultiStep>
                ),
              },
            },
            {
              return: ({ whyNot }) => ({
                interested: "no",
                whyNot,
              }),
            },
          ],
        },
      ],
      default: [
        {
          form: {
            values: () => ({
              whyNotSure: ["", []],
            }),
            render: ({ values, onNext, onBack }) => (
              <MultiStep onNext={onNext} onBack={onBack}>
                <FormStep
                  key="whyNotSure"
                  defaultValues={values}
                  resolver={zodResolver(
                    z.object({
                      whyNotSure: z.string().min(1, "Required"),
                    }),
                  )}
                >
                  <FormStepContent>
                    <FormStepHeading>Why are you not sure?</FormStepHeading>
                    <FormStepInputs>
                      <TextInput
                        name="whyNotSure"
                        label="Why?"
                        placeholder="Write your answer here..."
                      />
                    </FormStepInputs>
                    <FormStepRow>
                      <BackButton>Back</BackButton>
                      <NextButton>Submit</NextButton>
                    </FormStepRow>
                  </FormStepContent>
                </FormStep>
              </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.