Form schema

Yield

Learn how the yield element is used in the schema.


Usage

The yield element is used to yield values when navigating between steps. When values are yielded the onYield callback of the Formity component will be called.

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

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

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

import {
  Step,
  Layout,
  Row,
  TextField,
  NumberField,
  YesNo,
  NextButton,
  BackButton,
} from "./components";

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

export type Values = [
  Form<{ name: string; surname: string; age: number }>,
  Yield<{
    next: [{ name: string; surname: string; age: number }];
    back: [];
  }>,
  Form<{ softwareDeveloper: boolean }>,
  Yield<{
    next: [{ softwareDeveloper: boolean }];
    back: [];
  }>,
  Return<{
    name: string;
    surname: string;
    age: number;
    softwareDeveloper: boolean;
  }>,
];

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>
      ),
    },
  },
  {
    yield: {
      next: ({ name, surname, age }) => [{ name, surname, age }],
      back: () => [],
    },
  },
  {
    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>
      ),
    },
  },
  {
    yield: {
      next: ({ softwareDeveloper }) => [{ softwareDeveloper }],
      back: () => [],
    },
  },
  {
    return: ({ name, surname, age, softwareDeveloper }) => ({
      name,
      surname,
      age,
      softwareDeveloper,
    }),
  },
];

We need to use the Yield type and define the types of the values to be yielded when navigating to the next and previous steps.

export type Values = [
  // ...
  Yield<{
    next: [{ name: string; surname: string; age: number }];
    back: [];
  }>,
  // ...
  Yield<{
    next: [{ softwareDeveloper: boolean }];
    back: [];
  }>,
  // ...
];

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

export const schema: Schema<Values> = [
  // ...
  {
    yield: {
      next: ({ name, surname, age }) => [{ name, surname, age }],
      back: () => [],
    },
  },
  // ...
  {
    yield: {
      next: ({ softwareDeveloper }) => [{ softwareDeveloper }],
      back: () => [],
    },
  },
  // ...
];

The next function takes the input values and returns an array with the values to be yielded. Each array element will trigger the onYield callback function.

The back function works the same way with the difference that the values will be yielded when navigating to the previous steps.