Functional Props
React-Forminate provides a powerful way to make form fields dynamic through functional props. These props can accept either static values or functions that compute values based on form state and context.
Functional Props Overview
Several field properties can be either static values or dynamic functions:
- label
- required
- requiredMessage
- visibility
- disabled
Value Types
Each prop can accept:
- Static Value: Direct assignment of the expected type
label: "First Name"
- Function: Direct function that returns the value
label: ({ values }) => values.showLabels ? "First Name" : ""
- ComputedValue Object: Recommended approach for complex cases
label: {
fn: ({ values }) => `${values.title}'s Name`,
dependsOn: ["title"],
defaultValue: "Name"
}
ComputedValue Structure
The recommended way to use functional props is through the ComputedValue
type:
type ComputedValue<T> = {
fn: (context: FieldPropContext) => T;
dependsOn?: string[];
defaultValue?: T;
isAsync?: boolean;
};
FieldPropContext
The function receives a context object with:
{
fieldId: string, // Current field ID
values: object, // All form values
fieldSchema: object, // Current field schema
formSchema: object // Complete form schema
}
Usage Examples
Dynamic Label
{
fieldId: "greeting",
label: {
fn: ({ values }) =>
`Hello ${values.name || 'there'}`,
dependsOn: ["name"],
defaultValue: "Hello"
},
type: "text"
}
Conditional Required
{
fieldId: "spouseName",
required: {
fn: ({ values }) => values.maritalStatus === "married",
dependsOn: ["maritalStatus"]
},
type: "text"
}
Dynamic Visibility
{
fieldId: "studentDetails",
type: "group",
visibility: {
fn: ({ values }) => values.userType === "student",
dependsOn: ["userType"]
},
fields: [...]
}
Async Disabled State
{
fieldId: "premiumFeature",
disabled: {
fn: async ({ values }) => {
const status = await checkSubscription(values.userId);
return !status.isPremium;
},
dependsOn: ["userId"],
isAsync: true,
defaultValue: true
},
type: "checkbox"
}
Complete Example
const UserProfileForm = {
formId: "userProfile",
fields: [
{
fieldId: "userType",
type: "select",
label: "Account Type",
options: ["student", "professional", "retired"],
required: true
},
{
fieldId: "firstName",
type: "text",
label: {
fn: ({ values }) =>
values.userType === "professional"
? "Legal First Name"
: "First Name",
dependsOn: ["userType"]
},
required: true
},
{
fieldId: "employmentInfo",
type: "group",
label: "Employment Details",
visibility: {
fn: ({ values }) => values.userType === "professional",
dependsOn: ["userType"]
},
fields: [
{
fieldId: "company",
type: "text",
label: "Company Name",
required: {
fn: ({ values }) => values.userType === "professional",
dependsOn: ["userType"]
}
},
{
fieldId: "workEmail",
type: "email",
label: "Work Email",
disabled: {
fn: ({ values }) => !values.company,
dependsOn: ["company"]
}
}
]
},
{
fieldId: "studentId",
type: "text",
label: "Student ID",
requiredMessage: {
fn: ({ values }) =>
`Student ID is required for ${values.schoolName || 'your school'}`,
dependsOn: ["schoolName"]
},
visibility: {
fn: ({ values }) => values.userType === "student",
dependsOn: ["userType"]
}
},
{
fieldId: "submit",
type: "button",
label: {
fn: ({ values }) =>
`Submit as ${values.userType || 'user'}`,
dependsOn: ["userType"]
}
}
]
};