Form
Reach for this for any new or edit record form — fields: declares the shape, onSave: commits, autoAdvance: moves focus. Never hand-assemble a column of fields. Shown in the EDIT posture — a record loaded by id, every field seeded from it, and the delete affordance a new-record form does not have. It brings its own chrome, so this is the whole screen.
Spec of record: design-system/components/forms/FormView.d.ts
Live
Real widgets, built from the real kit. Turn a knob and it rebuilds; the theme bar above applies the design system's own tokens — including anything you changed under Customize — and the device selector uses the same sizes the golden baselines gate on, so what you see here is what CI holds the widget to.
Press Focus on any preview to take it to the full window — at a desktop width that renders most devices at 1:1, which is when the widget's own controls become clickable. The bar always states the device and the scale, so a shrunk preview says it is shrunk. Esc leaves.
loading holds the real pending state open; error throws a FormLoadException, whose message the form renders verbatim — the one place it shows a host's copy instead of its vocabulary.
Every field locked makes the record a read-only COMPOSITE: the save control and the delete affordance are both suppressed (§D19). A different screen, not a paint change.
Blanks the required Location field, so the save gate is on at rest and the modeline states what is missing.
auto lets each editor decide, half forces one column, full spans both.
A discrete commit — a picked option, a date, a toggle — moves to the next field. Never a keystroke.
Shows when you commit a field — this decides whether focus moves to the next one — press Focus to make the preview interactive.
The affordance a new-record form does not have.
Dart for these values
screen_form() What you can do in it
Capability the preview already carries that no knob can express — you reach it by using the widget. Worth knowing before concluding something is missing: most of this is only clickable once the preview is at Focus size.
- **Save** — the split button in the last inline-end header slot, never a footer button. It runs
submitting→saved→ pop; the preview holds the save open long enough to watch, because otherwise the state is over in a frame. These are the twoFormStatusvariants a KNOB cannot honestly offer: they are decided by the tap, and a control that faked one would show a state the widget never entered. - **A blocked save scrolls the first offending field into view** and the footer modeline states what is missing — required-blank and invalid are counted separately, because the remedies differ, and they sum into one badge.
- **Editing then backing out** raises the discard dialog; back never escapes an in-flight submit.
- **The IME walks the form** — single-line editors take next/done by position, so the keyboard never traps the reader mid-form.
What it is made of
The widgets this screen assembles, with their full API below. They used to live on a second entry of their own; one thing you choose gets one page.
FormScreen widget
The FLOORPLAN for creating or editing one record (`FormScreen.d.ts`). THE MODE IS A UNION, AND THE FORM ALWAYS HAS A WAY OUT (`FormScreen.d.ts`, 2026-10-20, #1639).
Full dartdoc
The FLOORPLAN for creating or editing one record (`FormScreen.d.ts`). ```dart FormScreen.edit( recordId: id, title: 'Observation', fields: observationFields, onLoad: load, onSave: save, onClose: () => Navigator.of(context).pop(), refOptions: resolveRefRows, capture: FormCapture(image: imageCapture), deletable: true, onDelete: remove, ) ``` THE MODE IS A UNION, AND THE FORM ALWAYS HAS A WAY OUT (`FormScreen.d.ts`, 2026-10-20, #1639). The contract's props are a union on `mode`, and this kit spells each arm as a NAMED CONSTRUCTOR, so a form that could never work no longer compiles: FormScreen.create takes the seeds and never a record id, a load or a Delete; FormScreen.edit REQUIRES recordId and onLoad, never takes a seed, and its Delete is a pair (deletable with onDelete). Both REQUIRE onClose. A host that computes the mode renders the two arms. **Every prop here is the contract's own** — onSeedLate, onClose, error and onRetry landed upstream at pin e04afca (where `onDelete` also took the `basedOnRevision` this kit's FormDeleteCallback always carried), and refOptions, capture and a NULLABLE fields at pin 30cd3b04. The lifecycle callbacks keep their Dart spellings: onSave and onDelete take the revision as a named argument, and onSeed / onSeedLate take a BuildContext, which is how a seed reaches the capture scopes above it. THE CLOSE REQUEST (`FormView.d.ts`, #506): a host's leave guard asks the mounted form through a `GlobalKey<FormScreenState>` — FormScreenState is the FormViewHandle (`dirty`, `requestClose()`), the key the parity gate already carves out, so the seam costs the contract no member.
FormScreen.create
| Knob | Type | Default | What it does |
|---|---|---|---|
| aside | Widget? | null | Context the author reads while editing. At large (>=1200) a secondary column beside the form, 320 wide on the ground at the card's inline end; below large it FOLDS (asideNarrow) rather than disappearing. The large test reads the SURFACE; the fields' pairing reads the CARD (`FormView.d.ts` THE… |
| asideNarrow | FormAsideNarrow fold · hide | FormAsideNarrow.fold | THE ASIDE FOLDS BELOW LARGE (`FormScreen.d.ts` `asideNarrow`, steady-core #1971): FormAsideNarrow.fold (the default) draws the aside as its own card below the form's card at expanded and medium, and as a collapsed disclosure at the card's foot at compact; FormAsideNarrow.hide draws nothing below… |
| asideTitle | String? | null | The aside's name (`FormScreen.d.ts` `asideTitle`, steady-core #1971): the folded card's heading at expanded and medium, the compact disclosure's summary ("More" when null), and at large the column's semantics label only. Without an aside it does nothing. |
| autoAdvance | bool | false | Moves focus to the next required, still-empty field after a field commits (a picker closes, a capture resolves). Default off. |
| band | FloorplanBand? | null | THE FORM CARRIES THE HOST'S BAND (`FormScreen.d.ts` `band`, steady-core #1777): the host's transient band — FloorplanBand, the type `RecordsScreen.band` and `DetailScreen.band` take, the contract's `ScaffoldHeaderBandProps` forwarded verbatim. It draws directly under this screen's bar on EVERY face… |
| banner | Widget? | null | THE FORM CARRIES A STANDING NOTICE (`FormScreen.d.ts` `banner`, steady-core #1786): `RecordsScreen.banner`'s node — the kit's `AppBanner`, one at a time — for a context true for the whole edit ("Editing pack: Spring. Changes go into the pack."). It sits under the bar and below a carried band, above… |
| capture | FormCapture? | null | What this form's capture tiles stage through — `FormView.d.ts`'s `capture`, forwarded VERBATIM and given no semantics here. **A CAPTURE FIELD IS READ-ONLY UNLESS ITS OWN KIND'S CAPTURE IS PRESENT** — `image` reads FormCapture.image, `file` reads FormCapture.file, `signature` and `drawing` read… |
| drawing | ImagePointDrawingResolver? | null | The drawing each `imagePoint` field places on, per field and per record — `FormView.d.ts`'s `drawing` (THE DRAWING, 2026-10-08), forwarded VERBATIM and given no semantics of its own: the kit's semantics are the contract's. The floorplan installs it as the ImagePointDrawingScope the image-point… |
| editors | Map<ColumnType, FieldEditor>? | null | A custom field-editor registry, keyed by field type, merged OVER the kit's own editors — the host media editors (image, file, signature, drawing, lat-long) land here. Null uses the kit's registry unchanged. |
| error | FormScreenError? | null | The host's load-face channel. A load failure the floorplan could not see — a precondition, a seed the host resolved itself, or an edit-mode record that no longer exists (which is an ERROR, never an empty face: a form with no record to edit is a failed load) — renders the load-error face WITH THE BAR… |
| fields * | List<FieldSpec>? | — | The fields, in order, with their sections, rules and cascades. **Null means the field SPECS are still resolving** — an engine's template, chosen before anything knows what fields exist at all. It ranks with LOADING and draws the same face, and it is a DIFFERENT AXIS from the record's values: a form… |
| leaveGuard | bool | true | Confirms before leaving with unsaved changes (default on). Off leaves immediately and discards them. |
| onClose * | VoidCallback | — | The bar's leading close/back, and where the form goes after a save. **Absent renders NONE**, and THE EXITS ARE DECLARED, NEVER INFERRED (`DetailScreen.d.ts` is the clause of record for both screens; it carries the same correction for `onBack`). This kit implemented the gate while disagreeing with… |
| onRetry | VoidCallback? | null | The load-error face's Retry, for a host-stated error and for the floorplan's own rejected or empty onLoad / mount onSeed alike (THE FLOORPLAN'S OWN FAILURE REACHES THE HOST'S RETRY, #1658): on the floorplan's own failure the face calls this FIRST, then loads (or seeds) again. Null renders no Retry… |
| onSave * | FormSaveCallback | — | Commits the values against the loaded revision. |
| onSeed | FormSeedCallback? | null | Create mode: the new record's seeded values (context defaults, the session principal id on principal-ref fields). |
| onSeedLate | FormSeedCallback? | null | Create mode: best-effort values that must never block first paint — a GPS fix, a slow lookup. Applied over the seed without dirtying the form, and never over a field the user has already edited. |
| optionsOf | FieldOptionsResolver? | null | An enum / enumList field's options for this person and record — `FormView.d.ts`'s `optionsOf` (a declared rule's gated choices, FieldRules.d.ts), forwarded VERBATIM to AppFormView.optionsOf and given no semantics here (#1900). FieldPlan's `use.rules` returns one (`FieldPlanForm.optionsOf`). Absent:… |
| prefill | FormPrefill? | null | Create mode: the opener's values applied OVER onSeed's, so a prefilled key replaces the seed's value for it (`FormScreen.d.ts` A CREATE FORM MAY OPEN PREFILLED, #1060). Absent, the default, overlays nothing; with no onSeed it lands on an empty map. * FILTERED, NEVER TRUSTED: an entry lands only when… |
| presence | Widget? | null | THE PRESENCE STACK (`FormScreen.d.ts` `presence`; `Presence.d.ts` EVERY FLOORPLAN CARRIES IT AS A KNOB, steady-core #1331): the `AppPresenceStack` of the scope this record joins. The HOST builds it; the screen never joins a channel. It rests in this screen's own bar immediately BEFORE the Save split… |
| refOptions | FormRefOptionsResolver? | null | A ref field's pickable rows, resolved at the screen tier — `FormView.d.ts`'s `refOptions`, forwarded VERBATIM and given no semantics here. Present, it SUPERSEDES each ref field's own option source, exactly as this kit's per-field `RefFieldConfig.cascadeOptions` supersedes `options`: the floorplan… |
| saveLabel | String | 'Save' | The Save split button's verb. Short, never a sentence. |
| sections | List<FormSectionSpec> | const [] | The form's section DECLARATIONS — each section's `label` and the one-line `purpose` the card states beside its fields (`FormView.d.ts` THE SECTION IS DECLARED ONCE, #846). AppFormView.sections' own type, forwarded verbatim and given no semantics here. The order is the fields'. |
| title * | String | — | The headline — 'New observation', or the record's name. |
FormScreen.edit
| Knob | Type | Default | What it does |
|---|---|---|---|
| aside | Widget? | null | Context the author reads while editing. At large (>=1200) a secondary column beside the form, 320 wide on the ground at the card's inline end; below large it FOLDS (asideNarrow) rather than disappearing. The large test reads the SURFACE; the fields' pairing reads the CARD (`FormView.d.ts` THE… |
| asideNarrow | FormAsideNarrow fold · hide | FormAsideNarrow.fold | THE ASIDE FOLDS BELOW LARGE (`FormScreen.d.ts` `asideNarrow`, steady-core #1971): FormAsideNarrow.fold (the default) draws the aside as its own card below the form's card at expanded and medium, and as a collapsed disclosure at the card's foot at compact; FormAsideNarrow.hide draws nothing below… |
| asideTitle | String? | null | The aside's name (`FormScreen.d.ts` `asideTitle`, steady-core #1971): the folded card's heading at expanded and medium, the compact disclosure's summary ("More" when null), and at large the column's semantics label only. Without an aside it does nothing. |
| autoAdvance | bool | false | Moves focus to the next required, still-empty field after a field commits (a picker closes, a capture resolves). Default off. |
| band | FloorplanBand? | null | THE FORM CARRIES THE HOST'S BAND (`FormScreen.d.ts` `band`, steady-core #1777): the host's transient band — FloorplanBand, the type `RecordsScreen.band` and `DetailScreen.band` take, the contract's `ScaffoldHeaderBandProps` forwarded verbatim. It draws directly under this screen's bar on EVERY face… |
| banner | Widget? | null | THE FORM CARRIES A STANDING NOTICE (`FormScreen.d.ts` `banner`, steady-core #1786): `RecordsScreen.banner`'s node — the kit's `AppBanner`, one at a time — for a context true for the whole edit ("Editing pack: Spring. Changes go into the pack."). It sits under the bar and below a carried band, above… |
| capture | FormCapture? | null | What this form's capture tiles stage through — `FormView.d.ts`'s `capture`, forwarded VERBATIM and given no semantics here. **A CAPTURE FIELD IS READ-ONLY UNLESS ITS OWN KIND'S CAPTURE IS PRESENT** — `image` reads FormCapture.image, `file` reads FormCapture.file, `signature` and `drawing` read… |
| deletable | bool | false | Renders the header Delete (edit mode only, danger confirm first) when onDelete is supplied. Default off — an app that CAN delete still says so per screen. |
| drawing | ImagePointDrawingResolver? | null | The drawing each `imagePoint` field places on, per field and per record — `FormView.d.ts`'s `drawing` (THE DRAWING, 2026-10-08), forwarded VERBATIM and given no semantics of its own: the kit's semantics are the contract's. The floorplan installs it as the ImagePointDrawingScope the image-point… |
| editors | Map<ColumnType, FieldEditor>? | null | A custom field-editor registry, keyed by field type, merged OVER the kit's own editors — the host media editors (image, file, signature, drawing, lat-long) land here. Null uses the kit's registry unchanged. |
| error | FormScreenError? | null | The host's load-face channel. A load failure the floorplan could not see — a precondition, a seed the host resolved itself, or an edit-mode record that no longer exists (which is an ERROR, never an empty face: a form with no record to edit is a failed load) — renders the load-error face WITH THE BAR… |
| fields * | List<FieldSpec>? | — | The fields, in order, with their sections, rules and cascades. **Null means the field SPECS are still resolving** — an engine's template, chosen before anything knows what fields exist at all. It ranks with LOADING and draws the same face, and it is a DIFFERENT AXIS from the record's values: a form… |
| leaveGuard | bool | true | Confirms before leaving with unsaved changes (default on). Off leaves immediately and discards them. |
| onClose * | VoidCallback | — | The bar's leading close/back, and where the form goes after a save. **Absent renders NONE**, and THE EXITS ARE DECLARED, NEVER INFERRED (`DetailScreen.d.ts` is the clause of record for both screens; it carries the same correction for `onBack`). This kit implemented the gate while disagreeing with… |
| onDelete | FormDeleteCallback? | null | Edit mode: deletes the record, behind the danger confirm. Rendered only when deletable. Carries `basedOnRevision` exactly as onSave does: a delete that cannot conflict-detect discards a revision it never saw. |
| onLoad * | FormLoadCallback | — | Edit mode: resolves the record's values and revision. |
| onRetry | VoidCallback? | null | The load-error face's Retry, for a host-stated error and for the floorplan's own rejected or empty onLoad / mount onSeed alike (THE FLOORPLAN'S OWN FAILURE REACHES THE HOST'S RETRY, #1658): on the floorplan's own failure the face calls this FIRST, then loads (or seeds) again. Null renders no Retry… |
| onSave * | FormSaveCallback | — | Commits the values against the loaded revision. |
| optionsOf | FieldOptionsResolver? | null | An enum / enumList field's options for this person and record — `FormView.d.ts`'s `optionsOf` (a declared rule's gated choices, FieldRules.d.ts), forwarded VERBATIM to AppFormView.optionsOf and given no semantics here (#1900). FieldPlan's `use.rules` returns one (`FieldPlanForm.optionsOf`). Absent:… |
| presence | Widget? | null | THE PRESENCE STACK (`FormScreen.d.ts` `presence`; `Presence.d.ts` EVERY FLOORPLAN CARRIES IT AS A KNOB, steady-core #1331): the `AppPresenceStack` of the scope this record joins. The HOST builds it; the screen never joins a channel. It rests in this screen's own bar immediately BEFORE the Save split… |
| recordId * | String | — | The record being edited; absent in create mode. |
| refOptions | FormRefOptionsResolver? | null | A ref field's pickable rows, resolved at the screen tier — `FormView.d.ts`'s `refOptions`, forwarded VERBATIM and given no semantics here. Present, it SUPERSEDES each ref field's own option source, exactly as this kit's per-field `RefFieldConfig.cascadeOptions` supersedes `options`: the floorplan… |
| saveLabel | String | 'Save' | The Save split button's verb. Short, never a sentence. |
| sections | List<FormSectionSpec> | const [] | The form's section DECLARATIONS — each section's `label` and the one-line `purpose` the card states beside its fields (`FormView.d.ts` THE SECTION IS DECLARED ONCE, #846). AppFormView.sections' own type, forwarded verbatim and given no semantics here. The order is the fields'. |
| title * | String | — | The headline — 'New observation', or the record's name. |
Types its knobs take
These are not things you choose — they are the shapes the knobs above expect. They live under this entry rather than in the navigation for exactly that reason.
FieldSpec support
Per-field static metadata describing how a single column renders in a `FormView`. Pure data — no widget references, no controllers.
| Field | Type | Default | What it does |
|---|---|---|---|
| allowOtherValues | bool | false | Whether an `enumValue` or `enumList` column accepts values outside enumValues (origin `AllowOtherValues:true` — 238/263 enums). When true an `enumValue` editor is an open combobox: a text input + filtered suggestions + a pinned `Add "{typed}"` row committing the typed value verbatim; an `enumList`… |
| columnType * | ColumnType | — | Column type — drives editor dispatch in `FieldEditorRegistry`. |
| decimalPlaces | int? | null | An `exactDecimal` field (and a quantity's number): at most this many digits after the point, counted as typed (`FormView.d.ts` AN EXACT DECIMAL IS ITS STRING). An intrinsic check. Null: any number of places, within `numeric`'s limit. |
| defaultUnit | String? | null | A quantity field's starting unit code; null starts at the first of units. |
| derive | FieldDeriver? | null | Recomputes this field's value from the live values map whenever any field changes — the in-form face of a write-time computed column. A derived field is **read-only by construction**: `FormController.isEditable` returns false for it, so a user edit can never be clobbered by the next unrelated… |
| editableIf | FieldPredicate? | null | Reactive `Editable_If` — when non-null, overrides isReadOnly: the editor accepts input only while this returns true. Null falls back to `!isReadOnly`. §D1. |
| enumDisplay | EnumDisplay | EnumDisplay.buttons | Display mode for `enumValue` columns (see EnumDisplay). Ignored for every other column type. Defaults to EnumDisplay.buttons. |
| enumValues | List<String>? | null | Pre-defined value set for `enumValue` / `enumList` / `color` editors. Null for other column types. |
| exactMax | ExactDecimal? | null | The inclusive upper bound, as exactMin. |
| exactMin | ExactDecimal? | null | An `exactDecimal` field (and a quantity's number): the inclusive lower bound, compared EXACTLY (ExactDecimal.compareTo, never through a float). An intrinsic check. A quantity's bound is in the value's own unit; a bound in another unit is the host's validator. |
| formatRules | List<FormatRule<Map<String, Object?>>>? | null | FORMAT RULES on the LOCKED face only (`FormView.d.ts` THE LOCKED FACE WEARS ITS RULE, #1006; `FormatRules.d.ts`): while the field is locked (read-only, editableIf false, a derived field) its value wears the first holding rule, as a detail field does. The SUBJECT is the field's value, and the ROW an… |
| helper | String? | null | Optional helper text rendered below the field label. Slice 18 surfaces this in `FieldCard`; emit threads it from the source per-field description when present. |
| initialValue | Object? Function()? | null | Optional seed for the field's value at form construction. A plain thunk — `() => DateTime.now()`, `() => 0.45` — invoked once when the controller builds (and again on reset). Returning `null` (or leaving it unset) starts the field empty. |
| inlineAction | FieldAction? | null | Field-scoped auxiliary action rendered beneath this field's editor — see FieldAction. Null renders no affordance. |
| isHidden | bool | false | Hidden fields are seeded into form state and round-trip through save, but render no editor — useful for a system key column carrying a generated id via initialValue. |
| isOwed | bool | false | Required LATER, never at save (`FormView.d.ts` A FIELD MAY BE OWED, #1496): the micro-label carries the required marker and the control is announced required, but the field never gates the save, never counts toward `FormController.requiredBlankCount` and never raises the required message, and its… |
| isReadOnly | bool | false | Static read-only flag — the editor is disabled whenever this is true. |
| isRequired | bool | false | Static "required regardless of state" flag — drives the required-blank validation in `FormController`. |
| label * | String | — | Human-readable label rendered as the editor's `labelText`. |
| listSeparator | String? | null | The write separator of an `enumList` / `refList` field — the column's own spelling (`ColumnDef.listSeparator`, threaded by the field plan, `bindFieldPlan`). Null writes `kEnumListSeparator`. The source platform's item separator is a per-column property; reads are separator-tolerant. |
| listValue | bool | false | An `enumList` (or a list of refs) whose value is a `List<String>`, not the joined string (`FormView.d.ts` AN ENUM LIST'S VALUE MAY BE ITS LIST, #1496): members verbatim, in held order, any text, never split, so a member may hold the separator. A held joined string is read through the list grammar… |
| maxDate | DateTime? | null | The latest offered day, inclusive, as minDate. |
| minDate | DateTime? | null | A `date` / `dateTime` field's earliest offered day, inclusive (`FormView.d.ts` A DATE CAN BE BOUNDED): reaches `AppDateField.min` and an intrinsic check. Null: unbounded. |
| noLabel | String? | null | The no-word of a `yesNo` field (origin `NoLabel`) — where the value is READ BACK rather than edited (a detail, a cell, a review line); the form's row never shows it. Null reads "No". §D4. |
| numberFormat | AppNumberFormat? | null | How a `number` / `decimal` / `percent` value reads on the field's LOCKED face (`FormView.d.ts` `FormField.numberFormat`; the rules are `DataTable.d.ts` NumberFormat's). THE LOCKED FACE READS AS THE CELL READS: while the field is not editable (read-only, editableIf false, a derived field) the box… |
| options | List<FieldOption>? | null | Labeled options for an `enumValue` / `enumList` field (`FormView.d.ts` AN OPTION HAS A LABEL, AND A RETIRED OPTION IS ONLY EVER HELD; steady-core #1491). When set it wins over enumValues: the stored value is FieldOption.value, every face shows FieldOption.label, and a FieldOption.retired option is… |
| override | FieldOverride? | null | The field's value comes from a WIDER SCOPE and may be overridden here (`FormView.d.ts` A FIELD MAY INHERIT ITS VALUE) — see FieldOverride. Null: an ordinary field whose value is its own, and nothing renders. |
| placeholderOf | String? Function(Map<String, Object?> values)? | null | What an EMPTY value MEANS, read against the live values (`FormView.d.ts` `FormField.placeholderOf`, 2026-10-09, #1217) — a nullable override whose blank is "auto", or a typical rate the blank falls back to. The answer paints in `--ink40` inside the editor's box while the value is blank: on the form,… |
| ref | RefFieldConfig? | null | Ref-column config — target table, choice-list stream, add-new builder. Null for every column that holds no ref: a `ref` column, and a LIST of refs (an `enumList` whose members are target keys — its editor is `kitRefListEditor`), carry one. |
| requiredIf | FieldPredicate? | null | Reactive `Required_If` — when non-null, overrides isRequired: the field is a save-gate only while this returns true. Null falls back to the static isRequired. §D1. |
| resetRule | ResetRule? | null | Reactive reset rule (origin `Reset_If` / `ResetOnEdit`). Null means the field is never auto-cleared. See ResetRule, §D1. |
| ruleLock | FieldRuleReading? | null | A DECLARED RULE's lock (`FormView.d.ts` `FormField.ruleLock`, FieldRules.d.ts THE BINDING): why the rule locks the field over the live and stored values, or null while it does not. The binding sets it (withFieldRules) and ANDs the same answer into editableIf; the form reads it only for THE WORDS… |
| ruleRefusal | FieldRuleReading? | null | A DECLARED RULE's save-time check (`FormField.ruleRefusal`): why the server would refuse THIS save's write of the field, or null when it permits. A refusal is the field's error line, in THE WORDS (`FormController.ruleRefusal`). The binding sets it. |
| section | String? | null | Optional section grouping. Null means "no section header" — the field still renders, but in the default un-headered section. Sourced from the source form's section settings. |
| showIf | FieldPredicate? | null | Reactive `Show_If` — when non-null, the field renders an editor only while this returns true over the form's current values. Null means "always visible" (the static default). A hidden-by-rule field leaves the layout, semantics, and focus tree; it does **not** null its value (only an explicit reset… |
| snakeName * | String | — | snake_case column name. Matches the key produced by `RowCodec<T>.encode(row)` and serves as the form-state map key. |
| span | FieldSpan | FieldSpan.auto | Layout span on tablet form factors (see FieldSpan). Phone always collapses to single column regardless of span. Defaults to FieldSpan.auto — the editor's natural width decides pairing. |
| stepValue | num? | null | Step increment for a `number` / `decimal` / `percent` editor (origin `StepValue`, e.g. `number_of_people` StepValue 1; a percent steps in the whole points it shows). When non-null the editor flanks the field with −/+ 48dp targets; the field still accepts typed input. Null renders a plain numeric… |
| suggestedValues | SuggestedValuesResolver? | null | Live suggestion source for an OPEN enum's combobox, and an OPEN enum list's entry surface (allowOtherValues) — typically the column's own already-used values, so free entry converges on the estate's vocabulary instead of minting near-duplicates. The editor subscribes once for its lifetime and merges… |
| temporal | TemporalSemantic | TemporalSemantic.instant | What a NAIVE `dateTime` value means (`FormView.d.ts` `temporal`, the column's `ColumnDef.temporal`, threaded by `bindFieldPlan`): TemporalSemantic.instant (the default) reads it in device-local time; TemporalSemantic.wallClock keeps the time as written. Read by a data table cell's typed entry and a… |
| units | List<QuantityUnit>? | null | An `exactDecimal` field that edits a QUANTITY (`FormView.d.ts` A QUANTITY IS A NUMBER AND ITS UNIT): the units it offers, in order. When set the value is a QuantityValue (`value`, `unit`), never a string; one unit is the box's suffix, several an `AppSelect` beside it. Null: a plain exact decimal. |
| validator | FieldValidator? | null | Value-level validation rule. Null means "any non-blank value is acceptable" (the static default) — this field is the ONLY way a form rejects a value on grounds other than blankness. The rule runs **after** the blank / required decision and only on a non-blank value, so it never re-implements… |
| yesLabel | String? | null | The yes-word of a `yesNo` field — the label of its one checkbox row, what ticking asserts (origin `YesLabel`, e.g. `report_request.is_report_package` → "Report Package"). Static: it is never re-worded per toggle. Null renders "Yes". |
FloorplanBand support
A floorplan's ONE TRANSIENT BAND — the contract's `ScaffoldHeaderBandProps` on both floorplans that declare one, stated once here rather than twice. `DetailScreen.d.ts` and `RecordsScreen.d.ts` each type their `band` member as that shared props type and forward it VERBATIM, so a Dart type per…
| Field | Type | Default | What it does |
|---|---|---|---|
| actionLabel | String? | null | Label for the ONE action beside message (the Undo pattern). |
| message | String? | null | The transient message. Null draws nothing. |
| onAction | VoidCallback? | null | Callback for that single action. |
FormCapture support
What a form's capture tiles stage through — the `FormScreen.d.ts` `capture` slot, which is `FormView.d.ts`'s `capture` resolver in the spelling THIS kit's editors read. `FormView.d.ts`'s own flutter clause names them: on this stack a capture tile resolves its value through an inherited capture…
| Field | Type | Default | What it does |
|---|---|---|---|
| canvas | CanvasCapture? | null | Stages a `signature` / `drawing` field's rasterized pad (CanvasCaptureScope). |
| file | FileCapture? | null | Stages a `file` field's pick (FileCaptureScope). |
| image | ImageCapture? | null | Stages an `image` field's camera/library pick (ImageCaptureScope). |
| location | LocationCapture? | null | Reads the device location a `latLong` field offers (LocationCaptureScope). |
| locationCenter | CaptureLocationCenterResolver? | null | Answers where an EMPTY `latLong` field's picker opens — `FormView.d.ts` `CaptureLocationPicker.fallbackCenter` (CaptureField.d.ts THE EMPTY FIELD'S OPENING CAMERA, #1373): per field and per record over the live values, a project's centroid say. It is shown while the picker's opening locate is… |
FormPrefill support
The overlay a create form opens with, and the two sets that filter it (`FormScreen.d.ts` A CREATE FORM MAY OPEN PREFILLED, #1060). A create form opened FROM a record arrives with that record's references already set: a child added from its parent's page, an entry logged against the record it was…
| Field | Type | Default | What it does |
|---|---|---|---|
| columns * | Set<String> | — | The TABLE's own columns: a key outside this set is dropped. |
| reserved * | Set<String> | — | The columns a prefill never sets — the key column, the scope columns, the audit columns, which are the seed's to stamp. A key inside this set is dropped, even when it is also in columns. |
| values * | Map<String, Object?> | — | What the opener names, keyed by column, in the values-map shape (`FormView.d.ts` THE VALUES MAP IS THE WIRE SHAPE) — a route's query, the record the form was opened from. |
FormScreenError support
The host's load-face channel's value (`FormScreen.d.ts` `error`, widened by THE NOTICE FACE, #506): the cause stated flat, one quiet line under it, and which face it renders. It is the floorplans' shared `FloorplanError` plus kind, and a CLASS rather than a record because the contract's `kind` is…
| Field | Type | Default | What it does |
|---|---|---|---|
| detail | String? | null | One quiet line under title. |
| kind | FormScreenErrorKind | FormScreenErrorKind.error | Which face renders it. |
| title * | String | — | The cause, stated flat. |
| Field | Type | Default | What it does |
|---|---|---|---|
| detail | String? | null | One quiet line under title. |
| title * | String | — | The cause, stated flat. |
FormSectionSpec support
One form section's DECLARATION (`FormView.d.ts` THE SECTION IS DECLARED ONCE; `FormSection`, Contained, 2026-09-29, #846). Fields JOIN a section by naming its id — its key, else its label — in `FieldSpec.section`; this entry only adds the words the Contained form card states beside them.
| Field | Type | Default | What it does |
|---|---|---|---|
| collapsed | bool? | null | The CONTROLLED collapse state of a collapsible section. Set, it is the state on every build: the head's toggle, the index's selection and a blocked save only ask through onCollapsedChanged, and the section moves when the host hands the new value back. A controlled section with no onCollapsedChanged… |
| collapsible | bool | false | When true the section's title is a disclosure toggle and its fields may collapse: out of the view and the focus order, still mounted, still gating the save (React `FormSection.collapsible`). Default false. |
| initiallyCollapsed | bool | false | The UNCONTROLLED seed of a collapsible section: read once, when the view first sees the section, and never re-seeded by a later value. Ignored while collapsed is set (React `FormSection.defaultClosed`). |
| key | String? | null | The section's stable identity, the string its fields name in `FieldSpec.section` (`FormView.d.ts` A SECTION HAS A KEY, #1496). When set, label is the title alone, free to change, and two keyed sections with one label stay two sections. Null: label is the identity, as before (React… |
| label * | String | — | The section's title (the title role); with no key, also the string its fields name in `FieldSpec.section`. |
| onCollapsedChanged | ValueChanged<bool>? | null | Reports the state the USER asks for — `true` to collapse: the head's toggle, or `false` when the index selects a collapsed section or a blocked save lands in one. Controlled or not; never at mount and never for a collapsed value the host changed (React `FormSection.onCollapsedChange`). |
| purpose | String? | null | One sentence stating what the section is for ("Who does the work, and where."), set in the purpose column beside the fields, or under the title when the card is stacked. Null renders the title alone. |
Where it lives
| Class | File |
|---|---|
| FormScreen | packages/app_widgets/lib/src/floorplans/form_screen.dart |