Form
Collect user information via inline or modal forms
Examples
The Friage.Form
component is used to render a form in your application. You can use it to collect user information, feedback, or any other data you need.
As with other Frigade components, a Form can contain multiple steps, each with its own fields and buttons.
The Form SDK is built on top of react-hook-form, which means you can use the majority of its features in your forms.
Simple Modal Form
Supported Field Types
The component supports the following field types:
select
radio
text
textarea
You can also define custom field types using the fieldTypes
prop.
For instance, if you want to build 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 }} />
It is also possible to conditionally render a field based on the value of another field by using the formContext provided by react-hook-forms.
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 { Form, type FormFieldProps, SelectField } from "@frigade/react";
<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>
);
},
}}
/>
Conditional Forms
If you want a form to conditionally skip a step based on the result of a previous step, you can use the visibilityCriteria
property in the step configuration.
For instance, the example below will jump directly to page 3 if the user picks a specific option on the first page/step:
steps:
- id: page-1
title: This is page 1
primaryButtonTitle: Next
fields:
- id: test-radio-1
type: radio
label: Radio group
options:
- label: Go to page 3
value: x
- label: Continue to page 2
value: y
- id: page-2
title: This is page 2
primaryButtonTitle: Next
visibilityCriteria: user.flowStepData("flow_fpJlqkbl", "page-1", "test-radio-1") != "x"
fields:
- id: test-text
type: text
label: Text field
- id: page-3
title: This is page 3
primaryButtonTitle: Finish
fields:
- id: test-radio-3
type: radio
label: Radio group
options:
- label: Radio 1
value: 1
- label: Radio 2
value: 2
- label: Radio 3
value: 3
visibilityCriteria
will work with both form data or any other Targeting condition.
Flow Configuration
The following props are available in the YAML Config defined in the Frigade Dashboard:
Possible values:
flow.back
, flow.complete
, flow.forward
, flow.restart
, flow.skip
, flow.start
, step.complete
, step.reset
, step.start
primaryButton.title
instead. The title of the primary buttonprimaryButton.uri
instead. The url to open when the primary button is clickedprimaryButton.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.Possible values:
flow.back
, flow.complete
, flow.forward
, flow.restart
, flow.skip
, flow.start
, step.complete
, step.reset
, step.start
secondaryButton.title
instead. The title of the secondary buttonsecondaryButton.uri
instead. The url to open when the secondary button is clickedsecondaryButton.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.React Component Props
as
Optional
as: ElementType
<any
, keyof IntrinsicElements
>
Optional component type to wrap the child components in. Use theas={Box}
component for inline placement or the as={Dialog}
component for modal placement.
If you want to wrap the Flow in a custom component (such as your own modal), you can pass the custom component here.
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.
onComplete
Optional
onComplete: FlowHandlerProp
Handler for when the Flow is completed.
If this function a promise that evaluates to false
, the Flow will not be marked as completed.
onDismiss
Optional
onDismiss: FlowHandlerProp
Handler for when the Flow is dismissed.
If this function a promise that evaluates to false
, the Flow will not be marked as dismissed.
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.