Form Layouts
Form Layouts
Organize your workflow forms into sections with custom grid layouts. This feature is completely optional - workflows without layouts will display fields in a simple list for backwards compatibility.
Basic Layout Structure
form:
layout:
sections:
- id: "section_id"
title: "Section Title"
description: "Optional description"
initial: true # Show this section during initial submission
grid:
- ["field1", "field2"] # Row with 2 fields
- ["field3"] # Row with 1 field (full width)
- ["field4", "field5", "field6"] # Row with 3 fields
# Optional responsive settings
responsive:
tablet: 2 # Max columns on tablet
mobile: 1 # Max columns on mobileSection Properties
id (required)
Unique identifier for the section. Used to reference sections in workflow steps.
title (required)
Display title shown in the section header with a gradient background.
description (optional)
Optional description displayed below the title to provide context.
initial (optional, default: false)
Set to true to show this section when the requestor creates the workflow. Only fields in initial: true sections are displayed and required to be filled during submission.
fields (optional)
Per-field layout overrides for this section. Keys are field names; values set layout attributes that apply only when that field appears in this section. Overrides layout.fields for the same field.
sections:
- id: summary
grid: [["amount", "tax"]]
fields:
amount:
align: right
bottom_border: true # only in this section
tax:
align: rightgrid (required)
Array of arrays defining field layout. Each inner array represents a row, and field names in the array are displayed side-by-side.
Example:
grid:
- ["name", "email"] # Two fields side-by-side
- ["phone"] # Single field, full width
- ["city", "state", "zip"] # Three fields in one rowLayout Attributes
Layout attributes control how a field looks in a section — alignment, borders, label placement. They are intentionally separate from field identity (type, label, required, etc.) so the same field can appear differently in different sections without duplication.
Attribute taxonomy
Field identity — defined on form.fields, survives layout changes:
| Attribute | Description |
|---|---|
type, label, required | Core identity |
options, validation, placeholder | Input behaviour |
width, align | Exception: valid on item_fields inside line_items (table column properties) |
Layout attributes — defined in layout.fields or section.fields:
| Attribute | Values | Description |
|---|---|---|
align | left | center | right | Value alignment in read-only display |
bottom_border | true | false | Full-width separator below the field |
span | full | half | auto | Grid column span hint |
valign | top | middle | bottom | Vertical alignment |
label_position | above | inline | hidden | Label placement |
layout.fields
Form-scope layout attributes applied to a field across all sections. Override per-section using section.fields.
form:
layout:
fields:
amount:
align: right # right-aligned in every section by default
notes:
label_position: abovePriority order
section.fields → layout.fields → field-level attribute (legacy fallback)Example: same field, two sections
form:
fields:
- name: amount
type: currency
label: Amount
required: true # identity only — no layout here
layout:
fields:
amount:
align: right # right-aligned everywhere unless overridden
sections:
- id: request_summary
title: "Summary"
grid:
- ["label_text", "amount"]
fields:
amount:
align: right
bottom_border: true # separator only in this section
- id: data_entry
title: "Request Details"
grid:
- ["amount"]
fields:
amount:
align: left # override: left-aligned in this section
bottom_border: falseResponsive Behavior
Control how layouts adapt to different screen sizes:
responsive:
tablet: 2 # Maximum 2 columns per row on tablets (641px - 1024px)
mobile: 1 # Maximum 1 column per row on mobile (<= 640px)When responsive settings are applied:
- Desktop: Uses the actual number of fields in each row (up to 6)
- Tablet: Limits columns to the
tabletvalue - Mobile: Limits columns to the
mobilevalue (typically 1 for vertical stacking)
Section Visibility in Workflow Steps
Control which sections are visible and editable at each approval step using view_sections and edit_sections:
workflow:
manager_approval:
name: "Manager Approval"
type: "decision"
approver: "manager"
view_sections: ["employee_info"] # Read-only sections (grayed out)
edit_sections: ["approval_info"] # Editable sections
on_approve:
continue_to: "hr_final"
hr_final:
name: "HR Final Approval"
type: "decision"
approver: "hr_manager"
view_sections: ["employee_info", "approval_info"] # Can view previous sections
edit_sections: ["hr_notes"] # Can edit HR notes section
on_approve:
end_workflow: trueDefault Behavior
If view_sections and edit_sections are not specified in a workflow step:
- All sections are displayed in view mode (read-only)
This ensures safe defaults - approvers can see all information but cannot accidentally modify fields unless explicitly allowed.
Complete Example
name: "Employee Onboarding"
description: "Multi-step onboarding process"
form:
layout:
sections:
- id: "personal_info"
title: "Employee Details"
description: "To be filled out by the new employee"
initial: true # Shown during workflow creation
grid:
- ["full_name", "personal_email"] # 2 columns
- ["phone_number"] # Full width
- ["start_date", "position"] # 2 columns
- id: "it_setup"
title: "IT Equipment Setup"
description: "IT department will configure equipment"
grid:
- ["laptop_choice"] # Full width
- ["monitor_request", "keyboard_request", "mouse_request"] # 3 columns
- ["additional_software"] # Full width
- id: "hr_verification"
title: "HR Verification"
description: "HR final verification and employee ID assignment"
grid:
- ["employee_id", "company_email"] # 2 columns
- ["hr_notes"] # Full width
responsive:
tablet: 2 # Max 2 columns on tablet
mobile: 1 # Stack vertically on mobile
fields:
# Personal Info Fields
- name: "full_name"
type: "text"
label: "Full Name"
required: true
- name: "personal_email"
type: "email"
label: "Personal Email"
required: true
- name: "phone_number"
type: "text"
label: "Phone Number"
- name: "start_date"
type: "date"
label: "Start Date"
required: true
- name: "position"
type: "text"
label: "Position / Title"
required: true
# IT Setup Fields
- name: "laptop_choice"
type: "radio"
label: "Laptop Choice"
display_as: "buttons"
options:
- { value: "macbook_pro", label: "MacBook Pro" }
- { value: "dell_xps", label: "Dell XPS" }
- { value: "lenovo_thinkpad", label: "Lenovo ThinkPad" }
- name: "monitor_request"
type: "checkbox"
label: "External Monitor"
- name: "keyboard_request"
type: "checkbox"
label: "External Keyboard"
- name: "mouse_request"
type: "checkbox"
label: "External Mouse"
- name: "additional_software"
type: "textarea"
label: "Additional Software Requirements"
# HR Verification Fields
- name: "employee_id"
type: "text"
label: "Employee ID"
required: true
- name: "company_email"
type: "email"
label: "Company Email Address"
required: true
- name: "hr_notes"
type: "textarea"
label: "HR Notes"
workflow:
it_provisioning:
name: "IT Provisioning"
type: "decision"
approver: "it_support"
view_sections: ["personal_info"] # Can view employee details
edit_sections: ["it_setup"] # Can edit IT equipment setup
on_complete:
continue_to: "hr_finalization"
hr_finalization:
name: "HR Finalization"
type: "decision"
approver: "hr_manager"
view_sections: ["personal_info", "it_setup"] # Can view both previous sections
edit_sections: ["hr_verification"] # Can edit HR verification
on_approve:
end_workflow: trueColumn-Based Layouts (Alternative to Grid)
Instead of row-based grids, you can use column-based layouts for vertical field stacking:
form:
layout:
sections:
- id: invoice_header
title: "Invoice Information"
columns:
- [customer_name, customer_address, customer_phone] # Column 1
- [invoice_no, invoice_date, due_date] # Column 2
column_widths: ["2", "1"] # First column 2x wider than secondColumn Widths
Control relative column widths with column_widths:
column_widths: ["2", "1"] # 2:1 ratio (first column is twice as wide)
column_widths: ["1", "1", "1"] # Equal width columns
column_widths: ["auto", "1fr"] # First column auto-sizes, second fills remaining spaceWidth Values:
- Numbers (
"1","2","3") - Relative proportions "auto"- Content-based width (useful for images/logos)"1fr"- Fills available space
Common Uses:
- Logo + text columns:
["auto", "1fr"] - Narrow + wide columns:
["1", "2"] - Equal columns:
["1", "1"]
Header and Footer Zones
Add branded headers and informational footers to your forms:
Header with Grid Format
form:
header:
grid:
- [company_logo, company_name, company_address]
fields:
- name: company_logo
type: image
source: "company"
height: 64px
show_label: falseHeader with Columns Format
form:
header:
columns:
- [company_logo] # Column 1: Logo
- [company_name, company_address, company_npwp] # Column 2: Text info
column_widths: ["auto", "1fr"] # Logo auto-sizes, text fills remainingFooter
form:
footer:
grid:
- [footer_note]
- [approval_date, approved_by, authorized_signature]Alternative Footer Format (Items-based)
Alternative footer format with explicit item control:
footer:
columns:
desktop: 3
tablet: 2
mobile: 1
padding: "16px"
background: "#f8f9fa"
items:
- type: message
content: "Document ID: GBB-FO-001 Ver 1.0/03-06-2024"
align: right
- type: field
field_name: approval_dateHeader/Footer Use Cases:
- Company branding (logos, addresses)
- Document metadata (version numbers, dates)
- Legal disclaimers and notes
- Signature fields and approval dates
- Reference numbers and barcodes
Fine-Grained Section Control (Mixed Sections)
For advanced scenarios where some fields in a section should be editable while others are read-only:
workflow:
finance_approval:
mixed_sections:
totals_section:
editable: ["authorized_signature", "approval_notes"]
# All other fields in totals_section are read-onlyThis allows precise control over field editability within a single section.
Visual Representation
When rendered, sections will appear with:
-
Section Header - Gradient blue background with:
- Section title (large, bold)
- Section description (smaller, gray)
- "Read-only" badge for view-only sections
-
Section Content - White background with:
- Grid-based field layout
- Responsive column adjustments
- Proper field spacing
-
Field States:
- Editable: Normal input fields with focus states
- Read-only: Grayed out with pointer-events disabled
Backwards Compatibility
Workflows without the layout section will:
- Display all fields in a simple vertical list
- Work exactly as before
- Require no changes to existing YAML files
Best Practices
-
Initial Section: Always mark at least one section with
initial: truefor workflow creation forms -
Logical Grouping: Group related fields into sections (e.g., "Personal Info", "Financial Details", "Approval Info")
-
Responsive Design: Use
responsivesettings to ensure forms work well on mobile devices -
Section Visibility: Use
view_sectionsandedit_sectionsto:- Show previous information to approvers (view)
- Allow approvers to fill in their specific sections (edit)
- Maintain data integrity by limiting edit access
-
Grid Layout:
- Use 2-3 columns for most forms
- Use full-width (1 column) for text areas and long text fields
- Use 3+ columns sparingly (only for very short fields like checkboxes)
-
Field Names: Ensure all field names in
gridarrays exist in thefieldslist -
Layout Attributes: Keep
align,bottom_border, and other visual attributes inlayout.fieldsorsection.fields, not onform.fields. Exception:alignandwidthonitem_fieldsinsideline_itemsstay on the field (they define table column properties).
Validation
The parser automatically validates:
- Section IDs are unique
- All field names in grids exist in the fields list
- All section references in workflow steps exist in the layout
- Grid structure is valid (arrays of arrays)
layout.fieldsandsection.fieldskeys match valid field names- Layout attribute values are within allowed sets (
alignmust beleft/center/right, etc.)
Invalid configurations will be caught when uploading the YAML file.