Skip to main content
View as Markdown

Form Field Groups

A twenty-field form rendered as one flat column asks the submitter to read every input before understanding any of them. The same fields under three headings — "About you", "Your experience", "Why us" — become something a person can scan and answer a section at a time.

fieldGroups declares those headings. Each entry is a label plus the field names that belong under it:

forms:
  - id: 1
    name: apply
    title: Apply for Senior Engineer
    submitTo: { table: candidates }
    fieldGroups:
      - label: About you
        fields: [first_name, last_name, email]
      - label: Your experience
        fields: [years_of_experience, github_url]
    fields:
      - { kind: table-field, column: first_name, required: true }
      - { kind: table-field, column: last_name, required: true }
      - { kind: table-field, column: email, required: true }
      - { kind: standalone, name: years_of_experience, inputType: number }
      - { kind: standalone, name: github_url, inputType: url }

Group Properties

Property Description Default
label Section heading rendered above the group's fields. Must be at least one character. Required.
fields Field names belonging to this section, in the order they should render. At least one required. Required.
visibleWhen Condition gating the whole section. Same shape and operators as a field's visibleWhen. Always visible.

fieldGroups is itself optional. Omit it and the form renders fields[] top to bottom with no headings — which is the right choice for a form short enough not to need signposting. When present, the array must declare at least one group.

Order Comes From the Groups

Once fieldGroups exists, it drives layout: sections render in array order, and each field renders in the position its group gives it. That means grouping can reorder a form without touching fields[] — the fields[] array keeps defining what the fields are, the groups define where they appear.

A field you never list still renders. It falls through to the bottom, after every section, in fields[] source order. Grouping half a form is therefore valid: the named fields get headings, the rest trail behind as an unlabeled block.

Conditional Sections

visibleWhen gates an entire section — label and every field under it — on the value of another field, using the same condition primitive as field-level rules:

fieldGroups:
  - label: Preferences
    fields: [wants_relocation]
  - label: Relocation
    fields: [relocation_country, relocation_date]
    visibleWhen: { field: wants_relocation, operator: eq, value: true }

The rule is evaluated server-side. On first render there are no answers yet, so a conditional section starts hidden and appears once its trigger is answered. On submit the rule is evaluated again, this time against the submitted values, and a section whose rule is false is treated as if it were never part of the form: its required fields do not block the submission.

Groups Versus Steps

Both carve a form into parts, and both take a visibleWhen. The difference is what the submitter sees at once.

Use When
fieldGroups All fields stay on one page and one scroll; headings give structure. Requires layout: single-page (the default).
steps Fields are split across screens with prev/next navigation and per-step validation. Requires layout: multi-step or one-question.

Last updated July 27, 2026

This documentation was written with AI, so errors or outdated content are possible. Sovrium is in beta — contributions and corrections are welcome.

Built with Sovrium