Building Workflows
How to define multi-step workflows with the flow builder.
A workflow is a sequence of steps, where each step is usually a Rilaykit form. The workflow builder allows you to chain these steps together and configure the navigation logic between them.
The flow
Builder
When you import from @rilaykit/workflow
, the flow
method is added to your ril
instance's prototype via module augmentation. This allows you to create a flow builder directly from your configured ril
instance.
1. Create your Form Configurations
First, you need a formConfig
for each step of your workflow. You'll create these using the standard form builder.
import { rilay } from '@/lib/rilay';
const personalInfoForm = rilay.form('personal-info').add(...).build();
const preferencesForm = rilay.form('preferences').add(...).build();
const reviewForm = rilay.form('review').add(...).build();
You can also pass a form
builder instance directly to a step. It will be built automatically.
2. Start the Flow Builder
Call .flow()
on your ril
instance to begin. You must provide a unique ID and a title for the workflow.
import { rilay } from '@/lib/rilay';
const workflowBuilder = rilay
.flow(
'user-onboarding',
'User Onboarding Workflow',
'A multi-step workflow to onboard new users' // Optional description
)
3. Add Steps
Use the .addStep()
method for each step in your sequence. You must provide at least a formConfig
(or a form
instance).
//...
.addStep({
id: 'personal-info',
title: 'Personal Information',
description: 'Tell us about yourself',
formConfig: personalInfoForm,
})
.addStep({
id: 'preferences',
title: 'Preferences',
description: 'Set your preferences',
formConfig: preferencesForm,
allowSkip: true, // This step is optional
requiredToComplete: false,
})
.addStep({
id: 'review',
title: 'Review & Feedback',
description: 'Review your information',
formConfig: reviewForm,
})
// ...
4. Configure Navigation and Hooks
You can configure the overall workflow behavior with the unified .configure()
method.
// ...
.configure({
navigation: {
allowBackNavigation: true, // Can users go back to previous steps?
showProgress: true, // Should the stepper be shown?
},
analytics: {
onWorkflowStart: (workflowId) => console.log(`Workflow ${workflowId} started.`),
onStepComplete: (stepId, duration) => console.log(`Step ${stepId} took ${duration}ms.`),
// ... other analytics hooks
}
})
// ...
5. Build the Configuration
Finally, call .build()
to get the final workflowConfig
object.
const workflowConfig = rilay
.flow(...)
.addStep(...)
.addStep(...)
.configure(...)
.build();
This configuration can now be passed to the <Workflow>
component, which will build it automatically if you pass the builder instance.
When to use .build()
Just like with forms, you often don't need to call .build()
on a workflow builder. The <Workflow />
component handles it for you.
You should call .build()
manually when you need the final, serializable WorkflowConfig
object, for example, to save it as JSON or for debugging.
Step Configuration
The object passed to .addStep()
has several options:
id
: A unique identifier for the step.title
: A human-readable title for the step, often shown in the stepper.description
(optional): A short description of the step.formConfig
: TheformConfig
object for this step's form.renderer
(optional): A custom renderer for the body of this specific step, allowing you to override the default<FormBody>
behavior.allowSkip
(optional, default:false
): Iftrue
, the user can skip this step. The<WorkflowSkipButton>
will appear.requiredToComplete
(optional, default:true
): Iffalse
, the user can complete the workflow without having visited this step.onAfterValidation
(optional): A powerful hook that runs after the step's form is successfully validated, but before navigating to the next step. See Advanced Workflows for details.permissions
(optional): Logic to determine if a user can access the step.dynamicConfig
(optional): Configuration for dynamically generating steps.
Complete Example: User Onboarding Workflow
Let's put it all together. Here is a full example of a 3-step user onboarding workflow.
First, we define the forms for each step:
// 1. Define the forms for each step
const accountForm = rilay
.form('account-form')
.add(
{ id: 'email', type: 'email', props: { label: 'Email' }, validation: { validators: [required(), email()] } },
{ id: 'password', type: 'password', props: { label: 'Password' }, validation: { validators: [required(), minLength(8)] } }
);
const profileForm = rilay
.form('profile-form')
.add(
{ id: 'firstName', type: 'text', props: { label: 'First Name' } },
{ id: 'lastName', type: 'text', props: { label: 'Last Name' } }
);
const confirmationForm = rilay
.form('confirmation-form')
.add({
id: 'terms',
type: 'checkbox', // Assumes a 'checkbox' component is registered
props: {
label: 'I agree to the terms and conditions',
},
validation: {
validators: [
custom(value => value === true, 'You must accept the terms')
]
}
});
About Validation
This example uses several built-in validators. To learn more about how validation works in Rilay, check out our in-depth Field and Form Validation guide.
Now, we use the flow
builder to chain them together into a workflow:
// 2. Build the workflow
export const onboardingWorkflow = rilay
.flow(
'onboarding',
'New User Onboarding'
)
.addStep({
id: 'account-creation',
title: 'Create Account',
formConfig: accountForm, // Notice we pass the builder directly
})
.addStep({
id: 'personal-info',
title: 'Your Profile',
formConfig: profileForm, // Rilay builds it for you
})
.addStep({
id: 'confirmation',
title: 'Confirmation',
formConfig: confirmationForm,
})
.configure({
navigation: {
allowBackNavigation: true,
showProgress: true,
}
});
This onboardingWorkflow
builder instance is ready to be passed to the <Workflow />
component, providing a complete multi-step form experience out of the box.