Form flowCondition

Form flow

Condition

Learn how the condition element is used in the flow.


Usage

The condition element is used to define a condition.

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

import { useCallback, useState } from "react";

import {
  Formity,
  type s,
  type Flow,
  type OnReturn,
  type ReturnOutput,
} from "@formity/react";

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

import { Form } from "./components/form";
import { Output } from "./components/output";

type Schema = {
  render: React.ReactNode;
  struct: [
    s.Form<{ working: string }>,
    s.Variables<{ company: string | null }>,
    s.Condition<{
      then: [s.Form<{ company: string }>];
      else: [];
    }>,
    s.Form<{ study: string }>,
    s.Return<{
      working: string;
      company: string | null;
      study: string;
    }>,
  ];
  inputs: Record<never, never>;
  params: Record<never, never>;
};

const flow: Flow<Schema> = [
  {
    form: {
      fields: () => ({
        working: ["yes", []],
      }),
      render: ({ fields, onBack, onNext }) => (
        <Form
          key="working"
          defaultValues={fields}
          resolver={zodResolver(
            z.object({
              working: z.string(),
            }),
          )}
          heading="Are you working?"
          content={[
            {
              type: "select",
              name: "working",
              label: "Working",
              placeholder: "Select an option",
              options: [
                { value: "yes", label: "Yes" },
                { value: "no", label: "No" },
              ],
            },
          ]}
          buttons={{
            back: null,
            next: "Next",
          }}
          onBack={onBack}
          onNext={onNext}
        />
      ),
    },
  },
  {
    variables: () => ({
      company: null,
    }),
  },
  {
    condition: {
      if: ({ working }) => working === "yes",
      then: [
        {
          form: {
            fields: () => ({
              company: ["", []],
            }),
            render: ({ fields, onBack, onNext }) => (
              <Form
                key="company"
                defaultValues={fields}
                resolver={zodResolver(
                  z.object({
                    company: z.string().nonempty("Required"),
                  }),
                )}
                heading="At what company?"
                content={[
                  {
                    type: "input",
                    name: "company",
                    label: "Company",
                    placeholder: "Company name",
                  },
                ]}
                buttons={{
                  back: "Back",
                  next: "Next",
                }}
                onBack={onBack}
                onNext={onNext}
              />
            ),
          },
        },
      ],
      else: [],
    },
  },
  {
    form: {
      fields: () => ({
        study: ["business", []],
      }),
      render: ({ fields, onBack, onNext }) => (
        <Form
          key="study"
          defaultValues={fields}
          resolver={zodResolver(
            z.object({
              study: z.string(),
            }),
          )}
          heading="What did you study?"
          content={[
            {
              type: "select",
              name: "study",
              label: "Study",
              placeholder: "Select an option",
              options: [
                { value: "business", label: "Business" },
                { value: "health", label: "Health" },
                { value: "technology", label: "Technology" },
                { value: "education", label: "Education" },
              ],
            },
          ]}
          buttons={{
            back: "Back",
            next: "Submit",
          }}
          onBack={onBack}
          onNext={onNext}
        />
      ),
    },
  },
  {
    return: ({ working, company, study }) => ({
      working,
      company,
      study,
    }),
  },
];

export default function App() {
  const [output, setOutput] = useState<ReturnOutput<Schema> | null>(null);

  const onReturn = useCallback<OnReturn<Schema>>((output) => {
    setOutput(output);
  }, []);

  if (output) {
    return <Output output={output} onStart={() => setOutput(null)} />;
  }

  return <Formity<Schema> flow={flow} onReturn={onReturn} />;
}

We need to use the s.Condition type with the corresponding types.

type Schema = {
  // ...
  struct: [
    // ...
    s.Condition<{
      then: [s.Form<{ company: string }>];
      else: [];
    }>,
    // ...
  ];
  // ...
};

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

const flow: Flow<Schema> = [
  // ...
  {
    condition: {
      if: ({ working }) => working === "yes",
      then: [
        {
          form: {
            fields: () => ({
              company: ["", []],
            }),
            render: ({ fields, onBack, onNext }) => (
              <Form
                key="company"
                defaultValues={fields}
                resolver={zodResolver(
                  z.object({
                    company: z.string().nonempty("Required"),
                  }),
                )}
                heading="At what company?"
                content={[
                  {
                    type: "input",
                    name: "company",
                    label: "Company",
                    placeholder: "Company name",
                  },
                ]}
                buttons={{
                  back: "Back",
                  next: "Next",
                }}
                onBack={onBack}
                onNext={onNext}
              />
            ),
          },
        },
      ],
      else: [],
    },
  },
  // ...
];

The if property is a function that takes the input values and returns a boolean value. If it is true, the elements in then are used. Otherwise, the elements in else are used.