Layout Schema
Top-level layout config
Section titled “Top-level layout config”type FormLayoutConfig = SinglePageLayoutConfig | WizardLayoutConfig | TabsLayoutConfig;type FormLayoutConfig = | SinglePageLayoutConfig | WizardLayoutConfig | TabsLayoutConfig | AccordionLayoutConfig;SinglePageLayoutConfig
Section titled “SinglePageLayoutConfig”interface SinglePageLayoutConfig { kind?: "single-page"; children?: FormLayoutNode[];}Use for:
- one-page custom UIs
- sectioned dashboards
- review or analyst screens
WizardLayoutConfig
Section titled “WizardLayoutConfig”interface WizardLayoutConfig { kind: "wizard"; steps: WizardStepConfig[];}Use for:
- multi-step flows
- onboarding
- staged data collection
- step-by-step review
TabsLayoutConfig
Section titled “TabsLayoutConfig”interface TabsLayoutConfig { kind: "tabs"; tabs: TabLayoutConfig[];}Use for:
- free section switching
- app-like shells with persistent submit
- analytical workflows that should not validate on navigation
Wizard steps
Section titled “Wizard steps”interface WizardStepConfig { id?: string; title: string; description?: string; children: FormLayoutNode[];}Rules:
stepsmust not be empty- each step must contain at least one node
- each field must belong to exactly one step
idis optional and auto-generated fromtitle
interface TabLayoutConfig { id?: string; title: string; description?: string; children: FormLayoutNode[];}Rules:
tabsmust not be empty- each tab must contain at least one node
- each field must belong to exactly one tab
idis optional and auto-generated fromtitle- switching tabs does not validate
AccordionLayoutConfig
Section titled “AccordionLayoutConfig”interface AccordionLayoutConfig { kind: "accordion"; sections: AccordionSectionConfig[];}Use for:
- progressive disclosure
- dense forms on mobile
- review flows where multiple regions can remain open
interface AccordionSectionConfig { id?: string; title: string; description?: string; children: FormLayoutNode[]; defaultOpen?: boolean;}Rules:
sectionsmust not be empty- each section must contain at least one node
- each field must belong to exactly one section
- first section defaults to open unless overridden
Node types
Section titled “Node types”type FormLayoutNode = | { kind: "section"; id?: string; title?: string; description?: string; children: FormLayoutNode[]; } | { kind: "group"; id?: string; columns?: 1 | 2 | 3; children: FormLayoutNode[] } | { kind: "field"; field: string } | { kind: "report"; report: string } | { kind: "explanation"; explanation: string };section
Section titled “section”Use section for semantic grouping and copy.
{ kind: "section", title: "Applicant", description: "Core identity data.", children: [ { kind: "field", field: "name" }, { kind: "field", field: "email" }, ],}Use group for visual grouping and column hints.
{ kind: "group", columns: 2, children: [ { kind: "field", field: "city" }, { kind: "field", field: "zip" }, ],}References a field id from the normalized form schema.
{ kind: "field", field: "name" }report
Section titled “report”References a report id.
{ kind: "report", report: "risk" }explanation
Section titled “explanation”References an explanation id.
{ kind: "explanation", explanation: "why" }Validation rules
Section titled “Validation rules”When layout is explicit:
- every field must appear exactly once
- reports may appear zero or one time
- explanations may appear zero or one time
- unknown references fail creation immediately
- missing fields fail creation immediately
Generated ids
Section titled “Generated ids”MLForm auto-generates ids for:
- sections
- groups
- wizard steps
Generated ids are slug-based and stable relative to config order.
Example layouts
Section titled “Example layouts”Single page with sections
Section titled “Single page with sections”{ kind: "single-page", children: [ { kind: "section", title: "Profile", children: [ { kind: "field", field: "name" }, { kind: "field", field: "email" }, ], }, { kind: "section", title: "Outputs", children: [{ kind: "report", report: "risk" }], }, ],}Wizard with review step
Section titled “Wizard with review step”{ kind: "wizard", steps: [ { title: "Profile", children: [{ kind: "field", field: "name" }], }, { title: "Assessment", children: [{ kind: "field", field: "score" }], }, { title: "Review", children: [ { kind: "report", report: "risk" }, { kind: "explanation", explanation: "why" }, ], }, ],}Tabs with result panel
Section titled “Tabs with result panel”{ kind: "tabs", tabs: [ { title: "Profile", children: [{ kind: "field", field: "name" }], }, { title: "Assessment", children: [ { kind: "field", field: "score" }, { kind: "report", report: "risk" }, ], }, ],}Accordion with progressive disclosure
Section titled “Accordion with progressive disclosure”{ kind: "accordion", sections: [ { title: "Profile", children: [{ kind: "field", field: "name" }], }, { title: "Assessment", children: [ { kind: "field", field: "score" }, { kind: "report", report: "risk" }, ], }, ],}