About this component

The Frigade Form component is one of the most versatile and customizable components in the Frigade SDK. It can be used for wide range of use cases including registration flows, surveys, feedback forms, and more. The component supports form validation (client and server-side), conditional fields, branching logic, and multi-step flows out of the box.

Examples

The following section contains a series of ready-to-use examples that demonstrate how to use the Frigade Form component in different scenarios.

Simple Modal Form

Churn Survey

Dynamic Fields

Sometimes you may want to conditionally render a dynamic field based on the value of another field. The example above dynamically changes the second dropdown based on the value of the first dropdown.

Branching Forms

This example shows how to implement branching in a form based on the user’s choice in the first step.

Supported Field Types

The component supports the following builtin field types that correspond to their respective HTML input types:

  • select
  • radio
  • text
  • textarea
  • checkbox

Overriding Field Attributes

You can override or add any attribute for a field by using the props property in the field configuration. For instance, this is useful if you want to use the text field type, but override the type to email or tel. It can also be used to add any attribute such as a css class, data, or styling.

steps:
  - id: step-1
    title: This is page 1
    fields:
      - id: email
        type: text
        props:
          type: email
          className: "my-custom-class"
          data-attr: "my-custom-data-attr"
          style:
            color: "red"

Custom Field Types

The Form SDK is built on top of react-hook-form, which means you can use the majority of its features in your forms. You can define your own custom field types using the fieldTypes prop. For instance, you can implement a simple calendar datepicker field type as such:

import { FormFieldProps } from "@frigade/react";
import * as Frigade from "@frigade/react";

function CalendarField({ field, submit }: FormFieldProps) {
  return (
    <div>
      <input type="date" onChange={field.onChange} value={field.value} />
    </div>
  );
}

// ...

<Frigade.Form flowId="my-flow-id" fieldTypes={{ calendar: CalendarField }} />;

It is also possible to conditionally render a field based on the value of another field by using the formContext provided by react-hook-form. For instance, if you want a custom field called company-size to show up when a user selects company in the customer-type field:

import { type FormFieldProps, SelectField } from "@frigade/react";
import * as Frigade from "@frigade/react";

<Frigade.Form
  flowId="myflowid"
  fieldTypes={{
    "company-size": (props: FormFieldProps) => {
      const customerTypeValue = props.formContext.watch("customer-type");

      if (customerTypeValue !== "company") {
        return null;
      }

      return <div>My custom conditional field</div>;
    },
  }}
/>;

Form Validation

The component supports client-side and server-side validation out of the box. You can define validation rules for each field in the form configuration using the pattern property with a regular expression. The example below shows how to validate an email field:

steps:
  - id: collect-intend
    fields:
      - id: email
        type: text
        required: true
        pattern:
          message: Please provide a valid email
          value: ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$

Server-side Validation

You can perform server-side validation by returning a Promise from the onPrimary event handler. If the promise resolves to false, the current step in the form will not be marked as completed. The onPrimary event handler also contains all form data collected in the session, which allows you to send the data to your server for validation or storage.

import { StepHandlerProp } from "@frigade/react";
import * as Frigade from "@frigade/react";

const App = () => {
  const handlePrimary: StepHandlerProp = async (step, event, properties) => {
    const response = await fetch("https://my-server.com/validate", {
      method: "POST",
      body: JSON.stringify(properties),
      headers: {
        "Content-Type": "application/json",
      },
    });

    if (response.ok) {
      return true;
    }

    // The current step in the form will be marked as completed
    return false;
  };

  return <Frigade.Form flowId="my-flow-id" onPrimary={handlePrimary} />;
};

Prefilling a form

Forms can be prefilled by using Dynamic Variables by linking the value of a field to the variables prop of the Form component. The example below shows how to prefill a form with the user’s name:

Flow Configuration

The following props are available in the YAML Config defined in the Frigade Dashboard:

steps
array

The individual steps/pages of the form

steps[].id
string

Unique identifier for the step. Do not change this once the step has been created.

steps[].title
string

The title of the step

steps[].subtitle
string

The description of the step

steps[].imageUri
string

Url to an image to display in the step

steps[].iconUri
string

Url to an icon to display in the step. This is only supported by the carousel checklist component.

steps[].videoUri
string

Url to a video to display in the step such as YouTube, Vimeo, or a direct link to an mp4 file

steps[].primaryButton
object

Config for the primary button in this step.

steps[].primaryButton.action
boolean,string

Primary button action. (defaults to step.complete).


Possible values: false, flow.back, flow.complete, flow.forward, flow.restart, flow.skip, flow.start, step.complete, step.skip, step.reset, step.start

steps[].primaryButton.target
string

Primary button URI target (defaults to _self).

steps[].primaryButton.title
string

Primary button title. If omitted, the primary button will not be shown.

steps[].primaryButton.uri
string

Primary button URI.

steps[].primaryButtonTitle
string

Deprecated: use primaryButton.title instead. The title of the primary button

steps[].primaryButtonUri
string

Deprecated: use primaryButton.uri instead. The url to open when the primary button is clicked

steps[].primaryButtonUriTarget
string

Deprecated: use primaryButton.target instead. The target of the primary button url (default: _blank; use _self to open in the same window). Setting it to # will open the existing page and dismiss any Frigade modals.

steps[].secondaryButton
object

Config for the secondary button in this step.

steps[].secondaryButton.action
boolean,string

Secondary button action. (defaults to step.complete).


Possible values: false, flow.back, flow.complete, flow.forward, flow.restart, flow.skip, flow.start, step.complete, step.skip, step.reset, step.start

steps[].secondaryButton.target
string

Secondary button URI target (defaults to _self).

steps[].secondaryButton.title
string

Secondary button title. If omitted, the secondary button will not be shown.

steps[].secondaryButton.uri
string

Secondary button URI.

steps[].secondaryButtonTitle
string

Deprecated: use secondaryButton.title instead. The title of the secondary button

steps[].secondaryButtonUri
string

Deprecated: use secondaryButton.uri instead. The url to open when the secondary button is clicked

steps[].secondaryButtonUriTarget
string

Deprecated: use secondaryButton.target instead. The target of the secondary button url (default: _blank; use _self to open in the same window). Setting it to # will open the existing page and dismiss any Frigade modals.

steps[].completionCriteria
string

Targeting that automatically completes the step. E.g.: user.property(‘connectedBank’) == true

steps[].startCriteria
string

Targeting that automatically blocks the step from starting until it becomes true. E.g.: user.property(‘connectedBank’) == true

steps[].visibilityCriteria
string

Targeting that automatically shows the step when it becomes true. E.g.: user.property(‘connectedBank’) == true

steps[].props
object

Override the default UI props for the corresponding component

steps[].fields
array

The data contained on the form step, typically text input boxes, multiple choice questions, etc.

steps[].fields[].id
string

Unique identifier for the step. Do not change this once the step has been created.

steps[].fields[].label
string

The label of the field

steps[].fields[].value
string

The default value of the field (used for prefilling). For checkboxes, use ‘true’ or ‘false’.

steps[].fields[].multiple
boolean

Whether the field can accept multiple values. Only used for the select type field.

steps[].fields[].type
string

The type of the field. The built-in supported types are: text, textarea, select, checkbox, and radio. If you are using custom form field types, the name here should match it.

steps[].fields[].placeholder
string

The placeholder of the field

steps[].fields[].maxLength
integer

The maximum length of the field

steps[].fields[].required
any

Whether the field is required or not. Use a string here to show a custom error message.

steps[].fields[].options
array

The options for the field. Only used for select fields.

steps[].fields[].options[].label
string

The label of the option

steps[].fields[].options[].value
any

The value of the option

steps[].fields[].pattern
object

The validation rules for the field. See documentation for more information.

steps[].fields[].pattern.value
string

Regex pattern to match the field against

steps[].fields[].pattern.message
string

The error message to display if the pattern does not match

steps[].fields[].props
object

Optional additional properties for the field. These will be passed to the frontend component as HTML attributes and merged with the default props for the given field type.

React Component Props

as

Optional as: ElementType<any, keyof IntrinsicElements>

Optional component to wrap the child components in, e.g. as={Dialog} will render the Flow in a modal Dialog. Defaults to Box.


css

Optional css: Interpolation<Theme>

Emotion CSS prop to apply to the component. See Theming documentation for more information.

Example usage:

<Frigade.Checklist css={{ backgroundColor: "pink", ".fr-button-primary": { backgroundColor: "fuchsia" } }} />

dismissible

Optional dismissible: boolean

Whether the Flow is dismissible or not


fieldTypes

Optional fieldTypes: FieldTypes

Custom field types to be used in the Form. You can use this to build your own custom form fields in a Form.

For example, if you want to use a custom field type called calendar:

import { Form, FormFieldProps } from "@frigade/react";

function CalendarField({ field, submit }: FormFieldProps) {
  return (
    <div>
      <input type="date" onChange={field.onChange} value={field.value} />
    </div>
  );
}

// ...

<Form flowId="my-flow-id" fieldTypes={{ calendar: CalendarField }} />;

flowId

flowId: string

The Flow ID to render. You can find the Flow ID in the Frigade dashboard.


forceMount

Optional forceMount: boolean

If true, the Flow will be mounted even if it has already been completed or dismissed. However, if the user does not match the Flow’s targeting, the Flow will not be mounted.


Optional modal: boolean

Register the Flow as a modal to prevent popup collisions (only one modal Flow will render at a time).


onComplete

Optional onComplete: FlowHandlerProp

Handler for when the Flow is completed. This is event is fired immediately after the user completes the Flow.


onDismiss

Optional onDismiss: FlowHandlerProp

Handler for when the Flow is dismissed (skipped). This is event is fired immediately after the user dismisses the Flow.


onPrimary

Optional onPrimary: StepHandlerProp

Handler for when primary button is clicked. If this function a promise that evaluates to false, the step will not be automatically completed when clicked.


onSecondary

Optional onSecondary: StepHandlerProp

Handler for when secondary button is clicked. If this function a promise that evaluates to false, the step will not be automatically completed when clicked.


variables

Optional variables: Record<string, unknown>

Variables to pass to the Flow. You can use variables in the Flow configuration to customize copy. For instance, you can use title: Hello, ${name}! in the Flow configuration and pass variables={{name: 'John'}} to customize the copy.

View definition