Form Flow Structure
This document explains the structure and organization of form flows, including steps, routing between steps, and data management.
Flow Definition
Section titled “Flow Definition”A form flow is a complete multi-step form with a defined structure:
import { flow } from '@getevy/evy-ui/flow';
const myFlow = flow({ id: 'registration-flow', // Unique identifier for the flow steps: [ // Array of step definitions // Step definitions go here ], queryParameters: [], // Optional: inputs that can be filled from query params});Flow Properties
Section titled “Flow Properties”id: Unique identifier for the flowsteps: Array of step definitions that make up the flowqueryParameters: (Optional) Array of input fields that can be pre-filled from URL query parameters
A step represents a single screen or page in the form flow:
import { step, textInput } from '@getevy/evy-ui/flow';
const personalInfoStep = step({ id: 'personal-info', // Unique identifier for the step blocks: [ // Array of content blocks and input fields textInput({ id: 'firstName' }), textInput({ id: 'lastName' }), ], next: 'address-info', // ID of the next step or special value});Step Properties
Section titled “Step Properties”id: Unique identifier for the stepblocks: Array of content blocks and input fields to displaynext: Where to go after this step (can be a step ID, ‘submit’, or a conditional routing object)i18nNamespace: (Optional) Custom i18n namespace for translations
Routing Between Steps
Section titled “Routing Between Steps”Static Routing
Section titled “Static Routing”The simplest form of routing is to specify the ID of the next step:
step({ id: 'step-1', blocks: [ /* ... */ ], next: 'step-2', // Go to step-2 after this one});Ending the Flow
Section titled “Ending the Flow”To end the flow and trigger submission:
step({ id: 'final-step', blocks: [ /* ... */ ], next: 'submit', // End the flow and trigger submission});Conditional Routing
Section titled “Conditional Routing”Route to different steps based on user input:
import { step, dropdown, nextFromInput } from '@getevy/evy-ui/flow';
step({ id: 'user-type', blocks: [ dropdown({ id: 'type', values: [ { value: 'individual', label: 'Individual' }, { value: 'business', label: 'Business' }, ], }), ], next: nextFromInput({ path: 'user-type.type', // Path to the input value to check routes: [ { value: 'individual', next: 'individual-form' }, { value: 'business', next: 'business-form' }, ], }),});In this example:
- The
pathpoints to the value we want to check (user-type.type) - The
routesarray maps possible values to their corresponding next steps - If the user selects “Individual”, they’ll go to the “individual-form” step
- If the user selects “Business”, they’ll go to the “business-form” step
Data Structure
Section titled “Data Structure”Form data is organized by step, with input values nested under their step IDs:
{ "step-1": { "firstName": "John", "lastName": "Doe" }, "step-2": { "email": "john.doe@example.com", "phone": "555-123-4567" }}Nested Data
Section titled “Nested Data”You can create nested data structures using dot notation in input IDs:
step({ id: 'contact-info', blocks: [ textInput({ id: 'contact.email' }), textInput({ id: 'contact.phone' }), textInput({ id: 'emergency.email' }), textInput({ id: 'emergency.phone' }), ], next: 'next-step',});This would result in the following data structure:
{ "contact-info": { "contact": { "email": "john.doe@example.com", "phone": "555-123-4567" }, "emergency": { "email": "jane.doe@example.com", "phone": "555-987-6543" } }}Flow Submission
Section titled “Flow Submission”When a flow reaches a step with next: 'submit', the flow is complete and the onSubmit callback is triggered. The callback receives a merged object containing all data from all steps.
The Form Flow API provides helper functions for working with submitted data:
import { mergeSteps, buildFormObject } from '@getevy/evy-ui/flow';
// Merge all step data into a single objectconst mergedData = mergeSteps(formData);
// Convert to FormData for API submissionconst formDataObject = buildFormObject(mergedData);Best Practices
Section titled “Best Practices”-
Use meaningful IDs: Choose descriptive IDs for flows, steps, and inputs.
-
Group related fields: Keep related fields together in the same step.
-
Limit step complexity: Don’t put too many fields on a single step.
-
Use conditional routing wisely: Complex routing can make flows difficult to understand and test.
-
Plan your data structure: Consider how your data will be used when designing your input IDs.
-
Consider validation requirements: Group fields that have interdependent validation in the same step.