Best Practices
Practical guidelines to keep your FormBuilder schemas clear, predictable, and easy to maintain.
Group your fields
Even if your overall structure depends on the form’s goal, it’s a good idea to wrap fields in at least one group.
Why
- Easier to condition visibility for a coherent block of fields.
- Keeps related inputs scoped and readable.
Important
readOnlyanddisableddo not cascade from a group to its children.
Define those flags on each child that needs them.
Example
{
"company_information": {
"type": "group",
"properties": {
"is_company": {
"component": "checkbox",
"label": "Is a company?"
}
},
"company_name": {
"component": "text",
"label": "Company name",
"visible": [{ "property": "is_company", "assertion": "isTrue" }]
}
}
}
English snake_case
Your schema defines the data produced by the form. Names must be explicit, stable, and readable.
Rules
- Always use English and snake_case:
first_name,invoice_date,total_amount. - Pick names that represent the value behind them (not the UI).
- Treat the schema as the source of truth for the output JSON structure.
DO
first_name,policy_start_date,contact_email
DON’T
FirstName,policyStart,input1
Example
{
"user": {
"type": "section",
"properties": {
"first_name": { "component": "text", "label": "First name" },
"last_name": { "component": "text", "label": "Last name" },
"age": { "component": "number", "label": "Age" }
}
}
}
Keep it simple
When conditions become complex (multiple groups of conditions; cross-field logic), don’t encode everything directly in the schema.
Base your visible / disabled / readOnly on a single, clear output from a dedicated workflow_validation module.
Why
- The schema stays readable and maintainable.
- Real complexity lives in a specialized module (versioned, tested).
Pattern
- Let your workflow compute a boolean or a small set of flags (e.g.,
can_edit_company_block,requires_manager_approval). - Use those flags in schema conditions.
Example
{
"manager_data": {
"type": "group",
"properties": {
"manager_comment": {
"component": "text",
"label": "Manager comment",
"visible": [
{
"property": "workflow.requires_manager_approval",
"assertion": "isTrue"
}
],
"disabled": [
{
"property": "workflow.can_edit_manager_comment",
"assertion": "isFalse"
}
]
}
}
}
}
Use non-breaking space
For translated labels or any text where the final punctuation (e.g., ?, !, :) must not wrap to the next line, insert a non-breaking space before the character.
Why
- Prevents the punctuation from appearing alone at line start.
- Produces a cleaner, more professional UI.
How
- Use a non-breaking space between the last word and the punctuation:
- HTML:
- Unicode:
\u00A0 - Shortcut: MacOS :
option + space, Windows :Ctrl+Maj+Space
- HTML:
Examples
Do you agree ?Amount to pay :Are you sure\u00A0?
Use this inside your translation values (the keys stay clean), for example:
{
"accept_terms": {
"component": "true_false",
"label": "t:accept_terms_label" // translation value: "Do you agree ?"
}
}
Quick checklist
- Wrap related fields in a group to simplify conditional display.
- Use English snake_case names that mirror the actual data.
- Push complex logic to a workflow/validation module and consume its outputs.
- Insert non-breaking spaces before punctuation to avoid orphan punctuation on new lines.
Keep schemas simple; push complexity to where it belongs. Your future self (and your teammates) will thank you.