Atlas Forms
Rendering Pipeline
FormRenderer transforms a parsed schema into a React tree in a predictable pipeline: schema normalisation → section grouping → visibility filtering → control ordering → layout grid → action bar. Understanding this pipeline helps when debugging unexpected rendering behaviour.
Pipeline Stages
- Schema parse —
parseSchema()validates and normalises the raw JSON. Sets default values, fills in missing optional properties. - FormEngine initialise — A
FormEngineinstance is created with the schema andinitialValues. The engine manages field state, computed values, and binding resolution. - Section grouping — Controls are grouped by their
sectionId. Controls without asectionIdgo into the root section. - Mode filtering — Controls with
modeVisibilitySettingsthat exclude the current mode are removed from the render list. - Visibility rule evaluation — Controls with a
visibilityRuleexpression are evaluated. Hidden controls are removed from the render list reactively. - Order sorting — Visible controls within each section are sorted by their
orderproperty (ascending). Controls without anorderare sorted by their array position. - Width layout — Controls with
widthproperties are grouped into rows using the 12-column grid. Controls of widthfullstart a new row;halffills 6 columns;thirdfills 4;quarterfills 3. - ControlRenderer dispatch — Each visible control is passed to
ControlRenderer, which dispatches to the registered control component based ontype. - Action bar — Form-level actions (submit, cancel, custom) are rendered below the last section in a fixed action bar.
Section Structure in Schema
// Form schema sections define grouping containers
{
"sections": [
{
"id": "applicant-section",
"title": "Applicant Information",
"order": 1,
"collapsible": false
},
{
"id": "documents-section",
"title": "Supporting Documents",
"order": 2,
"collapsible": true,
"defaultOpen": false
}
],
"controls": [
{ "id": "first-name", "type": "text", "sectionId": "applicant-section", "order": 1 },
{ "id": "last-name", "type": "text", "sectionId": "applicant-section", "order": 2 },
{ "id": "upload-id", "type": "file-upload", "sectionId": "documents-section", "order": 1 }
]
}
Width Grid Layout
| width value | Grid Columns | Fraction of Row |
|---|---|---|
full | 12 | 100% |
two-thirds | 8 | 66% |
half | 6 | 50% |
third | 4 | 33% |
quarter | 3 | 25% |
Row Packing Rules
The layout engine packs controls into rows greedily:
- A
fullwidth control always starts a new row. - Consecutive non-full controls are packed left-to-right until the row is full (12 columns).
- If the next control doesn't fit in the remaining columns, a new row starts.
- Example:
half+half= one row;half+third= one row (9 cols);third+third+third= one row.
ControlRenderer Dispatch
// packages/player-components-react/src/controls/ControlRenderer.tsx
// Simplified dispatch logic
const controlRegistry = getControlRegistry();
const ControlRenderer: React.FC<ControlRendererProps> = ({ control, ...ctx }) => {
const Component = controlRegistry.get(control.type);
if (!Component) {
console.warn(`No renderer registered for control type: ${control.type}`);
return <UnknownControlFallback type={control.type} />;
}
return <Component control={control} {...ctx} />;
};
Action Bar
The action bar renders below the last section. It includes:
- Submit button (hidden in view and design mode)
- Cancel button (optional — configured via
actionsin the schema) - Custom action buttons (e.g., Save Draft, Export, Print)