Flow elementsModule

Flow elements

Module

Learn how the module element is used in the flow.


Usage

The module element includes a nested flow that can be defined outside the main flow if needed.

TSX
type Schema = {
  render: React.ReactNode;
  struct: [
    s.Module<{
      render: React.ReactNode;
      struct: [s.Form<{ name: string; softwareDeveloper: string }>];
      inputs: Record<never, never>;
      values: Record<never, never>;
      params: Record<never, never>;
    }>,
    s.Module<{
      render: React.ReactNode;
      struct: [
        s.Condition<{
          then: [
            s.Form<{ expertise: string }>,
            s.Return<{
              name: string;
              softwareDeveloper: true;
              expertise: string;
            }>,
          ];
          else: [
            s.Form<{ interested: string }>,
            s.Return<{
              name: string;
              softwareDeveloper: false;
              interested: string;
            }>,
          ];
        }>,
      ];
      inputs: Record<never, never>;
      values: { name: string; softwareDeveloper: string };
      params: Record<never, never>;
    }>,
  ];
  inputs: Record<never, never>;
  params: Record<never, never>;
};

const flow: Flow<Schema> = [
  {
    module: [
      {
        form: {
          fields: () => ({ name: ["", []], softwareDeveloper: ["", []] }),
          render: ({ fields, next }) => (
            <AboutMeForm fields={fields} onNext={next} />
          ),
        },
      },
    ],
  },
  {
    module: [
      {
        condition: {
          if: ({ softwareDeveloper }) => softwareDeveloper === "yes",
          then: [
            {
              form: {
                fields: () => ({ expertise: ["", []] }),
                render: ({ fields, back, next }) => (
                  <ExpertiseForm fields={fields} onBack={back} onNext={next} />
                ),
              },
            },
            {
              return: ({ name, expertise }) => ({
                name,
                softwareDeveloper: true,
                expertise,
              }),
            },
          ],
          else: [
            {
              form: {
                fields: () => ({ interested: ["", []] }),
                render: ({ fields, back, next }) => (
                  <InterestedForm fields={fields} onBack={back} onNext={next} />
                ),
              },
            },
            {
              return: ({ name, interested }) => ({
                name,
                softwareDeveloper: false,
                interested,
              }),
            },
          ],
        },
      },
    ],
  },
];

Each module schema must be compatible with the parent flow:

  • render must match the flow's render.
  • inputs must be a subset of the flow's inputs.
  • values must be a subset of the flow's values at that point.
  • params must be a subset of the flow's params.

Separate files

Modules are most useful when defined in separate files, which keeps the flow clean and allows reuse.

modules/about-me.tsx:

TSX
import type { Module, s } from "@formity/react";

export type Schema = {
  render: React.ReactNode;
  struct: [s.Form<{ name: string; softwareDeveloper: string }>];
  inputs: Record<never, never>;
  values: Record<never, never>;
  params: Record<never, never>;
};

export const module: Module<Schema> = [
  {
    form: {
      fields: () => ({ name: ["", []], softwareDeveloper: ["", []] }),
      render: ({ fields, back, next }) => (
        <AboutMeForm fields={fields} onBack={back} onNext={next} />
      ),
    },
  },
];

modules/condition.tsx:

TSX
import type { Module, s } from "@formity/react";

export type Schema = {
  render: React.ReactNode;
  struct: [
    s.Condition<{
      then: [
        s.Form<{ expertise: string }>,
        s.Return<{
          name: string;
          softwareDeveloper: true;
          expertise: string;
        }>,
      ];
      else: [
        s.Form<{ interested: string }>,
        s.Return<{
          name: string;
          softwareDeveloper: false;
          interested: string;
        }>,
      ];
    }>,
  ];
  inputs: Record<never, never>;
  values: { name: string; softwareDeveloper: string };
  params: Record<never, never>;
};

export const module: Module<Schema> = [
  {
    condition: {
      if: ({ softwareDeveloper }) => softwareDeveloper === "yes",
      then: [
        {
          form: {
            fields: () => ({ expertise: ["", []] }),
            render: ({ fields, back, next }) => (
              <ExpertiseForm fields={fields} onBack={back} onNext={next} />
            ),
          },
        },
        {
          return: ({ name, expertise }) => ({
            name,
            softwareDeveloper: true,
            expertise,
          }),
        },
      ],
      else: [
        {
          form: {
            fields: () => ({ interested: ["", []] }),
            render: ({ fields, back, next }) => (
              <InterestedForm fields={fields} onBack={back} onNext={next} />
            ),
          },
        },
        {
          return: ({ name, interested }) => ({
            name,
            softwareDeveloper: false,
            interested,
          }),
        },
      ],
    },
  },
];

Then import and use them in the flow.

TSX
import * as aboutMe from "./modules/about-me";
import * as condition from "./modules/condition";

type Schema = {
  render: React.ReactNode;
  struct: [s.Module<aboutMe.Schema>, s.Module<condition.Schema>];
  inputs: Record<never, never>;
  params: Record<never, never>;
};

const flow: Flow<Schema> = [
  { module: aboutMe.module },
  { module: condition.module },
];