Grid Views

Grid Views

Grid Views

A Grid View declares a custom surface in model source. Its indentation describes what the person sees, changes, and does; ordinary Grid expressions keep their existing meaning and run in the native runtime.

input qty IS integer = 2 VALIDATE 1..10 PRESENT Slider
price IS currency = 19.99
total IS currency = qty * price
STATE placed = FALSE
 
SURFACE Order AS "Order"
  qty AS "How many?"
  [price, total]
  "Place order" -> placed = TRUE
  "Order placed." IF placed
END

SURFACE is contextual. A complete declaration header requires a newline; surface = 4 and SURFACE Order = 5 retain their existing binding meanings. Use spaces for indentation and align END with its declaration header.

A value may have an AS label and an IF or UNLESS guard. The last guard on the line applies to the whole view. Parenthesize an expression-level guard. Brackets arrange outline items across commas and down semicolons; write show [1, 2] when the array itself is the value to display.

A declaration's trailing PRESENT Slider chooses its usual element. An explicit kind on the view line takes precedence; ownership and show/edit still decide whether the placement can write. A local or imported element alias may also be used: PRESENT QuantityField. Native elements must declare a value-bearing subject; composites must accept exactly one parameter. A composite's subject controls must match show or edit; an incompatible direction is a diagnostic. Explicit element names inside the composite avoid recursively selecting its own presentation. See declared presentation.

Use named ARRANGE regions for merged cells:

SURFACE Dashboard
  ARRANGE [header, header; navigation, content]
    header: "Overview"
    navigation: "Sections"
    content: "Details"
END

Repeated names must fill one rectangle. Every region has exactly one labelled content block; the compiler reports missing, unused, duplicate, or nonrectangular regions. Positions and spans become static layout metadata, without model reads.

In Code, select ARRANGE in the outline to edit Named regions. Add or remove rows and columns, then choose the region for each cell. Rename a region without changing its content. Add region creates a name and placeholder content; assign it at least one cell. Remove [name] and content stages removal and lists the affected regions before Apply layout changes source. Retained content keeps its bindings, guards, comments and embedded payloads. Nested and flat labelled blocks are supported, and the whole edit uses one editor Undo step. Every region must remain one filled rectangle, with a distinct name and at least one cell; the compiler explains invalid arrangements without applying them.

To start a layout, choose Named region layout in Add element or page. Select a region label such as content: to add elements inside it or move existing elements there. Content written on the same line, such as content: NumberInput quantity, appears as a separate selectable child with its own properties. The region's visibility condition stays on the region. Simple text, binding and option edits keep the inline spelling. Structural changes and native event/slot edits expand the affected region onto indented lines automatically, preserving conditions, comments and multiline payloads. The expansion and requested change share one editor Undo step. A container inside a region has its own Inside selected element destination, distinct from Inside selected region. Moves across declaration, page or repeater scopes show a source review before Apply. Matrix comments stay in place when names or cell assignments change. Resizing retains every matrix comment in its original order above the new cells, inside the matrix brackets; Properties explains this before applying. Comment text and line endings are preserved even when their former rows or columns are removed. The visual matrix supports up to 64 rows, 64 columns and 256 regions; larger matrices remain in Code. See the region layout example.

Pages use PAGE Name(parameters) AS "Title" AT "path/:parameter". Reusable ELEMENT Name(parameters) … END declarations hold view outlines or contracts that map phrases to properties, lenses, slots, and events. Contracts are libraries; the outline scanner does not contain a widget vocabulary. Phrases match longest first and may continue on directly indented lines. A blank line detaches a continuation. Operator-led phrases start their own line. Boolean split lenses name each callback and its fixed value: open means open, set by onOpen(TRUE), onClose(FALSE) : boolean. A close-only lens names just onClose(FALSE). These callbacks use the same write guards and Form staging as other lenses.

local declares private browser state. SCRIPT <js>…</js> and inline js"…" contain real JavaScript; STYLE <css>…</css> contains real CSS. These payloads are verbatim. JavaScript receives model values through explicit USING … AS bindings; it is never a second evaluator for Grid expressions. Code checks named helpers against known standard/native property contracts and native asks signatures at each use. For example, a helper returning text for Stack gap receives a type error at that helper's Grid reference. Multiple uses of the same helper keep their own expectations. Ordinary property helpers receive a context object; a bare named asks helper receives positional arguments. The JavaScript module remains editable at its declaration. These checks also supply contextual parameter types inside unannotated local helper declarations, using the existing TypeScript worker. Multiple callers contribute a union of input types, and author annotations take precedence. Completion and diagnostics still point to authored source; the generated types are not edits. Imported library helpers remain outside these named-export checks.

An imported element can name a tier-2 adapter with adapter exportName inside its ELEMENT … FROM "react:…" contract. Define that export in the surface's or source library's SCRIPT <jsx>…</jsx>. JSX stays verbatim until the selected browser preparation step; the model compiler never executes it. For example, inside an existing locked element contract:

  subject means value, set by onChange : number
  caption means label : string
  on reset tells onReset()
  parts label, value
  adapter renderControl

The corresponding module can wrap the locked export:

import { Control } from "react:your-controls@1";
import { useRef } from "react";
export function renderControl({ subject: [value, setValue], caption, tell, parts, className }) {
  const root = useRef(null);
  return <label ref={root} className={className} {...parts.label}>
    {caption}
    <Control value={value} onChange={setValue} {...parts.value} />
    <button onClick={() => tell("on reset")}>Reset</button>
  </label>;
}

Here your-controls represents your installed, locked package, and Control must be one of its admitted exports. Adapter props use contract phrase names; a lens is [value, setValue], the default body is children, and named slots retain their phrase names. Multiword phrases use bracket access. tell accepts the full declared event phrase and its positional arguments. parts.label is { "data-part": "label" }: spread it onto the actual styleable DOM element, or onto a component that forwards DOM attributes. An adapter chooses that mapping; a foreign component's internal DOM is not guessed. parts, tell, className and the default children slot cannot collide with other adapter phrase names.

Hooks and refs use the host's React instance. Static imports resolve only to the contract's locked package references (or an unambiguous package name), React, React DOM, and the React JSX runtime. Unlisted imports refuse loading. Adapters retain ordinary lens conversion, validation, Form staging and event write guards. They require the existing trusted workspace or package sandbox, are React-only, and are prepared as self-hosted JavaScript modules in published packages; the package does not evaluate JSX source or load a JSX compiler at runtime.

See the SCRIPT contract exercise.

Use SCRIPT <jsx>…</jsx> when a helper produces React elements or component-valued properties. It is real JavaScript with JSX, with the same explicit Grid value bridge and trust requirements. React is available, and import React, { useMemo } from "react" uses the renderer's existing React instance. Component imports use the View's exact locked library references. Code checks JSX and maps errors and completion edits to the original block; headless View CHECKs use the same React declarations. Ordinary <js> scripts do not gain React globals. Preview prepares selected JSX when loading the module; packaged Views and Vue/Svelte/Solid archives prepare it during export and load ordinary module files. Library scripts retain their separate namespaces. See the JSX helper example, which supplies a custom day button through an admitted component property. Contract-selected adapters also support lens pairs, tell and slot wiring as described above. The adapter example wraps a pinned chooser, focuses it through a private ref, and retains ordinary Grid selection and event handling. Code completes control.subject and parts.help, and reports invalid contract fields and tell phrases at their original JSX bytes. Locked component imports also offer the native props retained by their contracts. For example, changing the chooser's options={options} to options={1} reports a type error at that JSX attribute. Named/default imports and unambiguous package aliases use the exact admitted export list; unknown exports and unadmitted imports still report errors.

Re-importing a package also projects bounded component prop declarations into its library lock. These retain required and unmapped props, unions and callback signatures for Code, without loading package code. Older locks use the contract as a fallback. Recursive serializable shapes are retained as bounded type graphs (a record repeated across props is one definition); a React-node value is unknown, while the record that holds it stays structural; shapes past 16 levels, 2,048 distinct types for a contract (4,096 for a component) or the byte limits become unknown. These are bounded declarations, not a copy of the package type graph. Each View owns its import declarations, so two Views can use different package versions without sharing types. Headless CHECK uses the same projected declarations and source maps, without loading package code.

Unknown event phrases and extra captured arguments are refused; a declared but unused event does nothing. Lens setters retain the original conversion, revision, permission and Form rules even if an event shares the native callback name. A phrasebook can replace the adapter while retaining the locked component. An imported contract with parts needs an explicit component adapter before it is placed. Spread parts.label, parts.value, and the other declared attributes on the corresponding elements; the compiler diagnoses a missing adapter with the repair spelling. Declaring names cannot identify a third-party DOM node. Missing exports and render/event failures use source-bound reporting; imported selections link to their caller's USE while retaining the definition origin. Adapter authoring metadata is bounded to 32 KiB, 64 events and 64 parts per use.

Native event contracts can retain their callback signature after tells, for example on pick tells onPick(chosen) : (chosen: { label: string }) => void. Known literal inputs and locals also check tuple lengths and positions, optional trailing tuple entries, literal choices and discriminated record alternatives. Lens converter glue receives separate model-side and foreign-side expectations: goes in maps the model type to the declared element value type, and comes out maps back. Known scalar and record types are retained; raw collection wire shapes remain unknown. Grid lambda converters diagnose known return mismatches during admission. The raw model value is not checked against the foreign phrase type before its declared read converter runs.

Imported SCRIPT helpers are checked in isolated library documents with their contract parameter and result types. Their diagnostics point to the caller's USE statement; imported bytes cannot be edited through that anchor. Code and headless CHECK share helper contextual typing and source-map handling.

These checks use admitted literal data; they do not evaluate formulas. Dynamic values retain the ordinary conservative type checks.

The importer now preserves the types of admitted event values, including dates, records and optional fields; older pinned contracts need an explicit re-import to gain these annotations. Inline JavaScript in the handler receives the declared values and Code checks member access and offers completion. Untyped event values remain unknown in Code. Event values shadow same-named locals; an explicit USING alias overrides that capture. A selected event member retains its type through USING, and the event scope ends with its handler. Named helpers used inside an arrow receive captured fields on their normal context object. Trailing raw DOM events remain excluded. Rest, overloaded and nonserializable callbacks need adapters. Grid admission also checks finite imported record, array, union and callback shapes against inferred property/lens values. In event handlers it checks nested declared fields, nullable payloads and array accesses. Unknown aliases, index signatures and complex foreign types stay open. This bounded contract reader does not execute foreign code or validate runtime payloads. Grid autocomplete uses those declared records too: payload.customer. offers customer fields, and payload.items[1]. offers the array item's fields. Optional access retains ?; choosing a name with spaces inserts quoted brackets. A union offers fields common to its non-null alternatives, and shadowed parameters keep their own scope. Unknown aliases and arbitrary function results do not acquire invented fields. These hints have a separate bounded authoring budget; a large contract remains usable even when Code withholds some suggestions. See the typed day-click exercise.

Built-in Kanban, Calendar and Map handlers also carry event types into Code. Destination columns, calendar start/end values and map selection identifiers are strings; calendar patches map column names to strings. Known model row fields supply completion and scalar hints for card, event, feature and row. Numeric fields allow numbers or exact numeric text, so narrow them before using representation-specific methods. Nested, dynamic and resident-table fields stay unknown; previous Kanban column values are unknown because the source column can hold any value. Field hints are bounded to 256 names and 16 KiB; omitted names retain unknown access. Grid handlers also check direct field reads against complete known row shapes: card.titel reports the declared fields, and column.value explains that the destination column is a string. This covers model/local updates, guards, notifications and page arguments. LET/LAMBDA parameters retain their own scope. Unknown or truncated rows, nested data and opaque imported callback types stay open. These checks do not validate runtime payloads. In Grid handlers, type card. (or the event's row, event or feature name) to choose a known field. Suggestions work inside balanced calls and retain lexical scope: a local parameter named card does not borrow the event's fields. Choosing a field containing spaces or punctuation inserts bracket syntax, such as card["order total"]; optional reads retain their ?. A reusable element used with different row schemas offers only fields common to those uses. Unknown event records do not offer unrelated model names. Large or incomplete expressions that cannot establish scope keep source editing without field suggestions. Nested built-in row inference and complex foreign callback types remain separate work; finite imported event records use their declared shapes. The ticket-selection exercise uses a private browser message and never writes model inputs. Calendar's end column setting can be written on its own indented line; a closing END, END SURFACE or END ELEMENT still needs the declaration's indentation.

The formatter retains foreign payload bytes, comments, and expression spelling. Imported operator-led phrases use their admitted contract vocabulary through format_source_with_resolver. The compiler formatter CLI can resolve local .grid libraries with --mode fmt --library-root <directory>; imports must remain inside that directory. Without a resolver it preserves unknown imported phrases rather than guessing their boundaries. Native package contracts use the same locked resolver supplied to the compiler.

An arrow can pin its rule identity with a literal key:

"Place order" key :place_order -> placed = TRUE

Changing the label or moving the arrow through presentation wrappers keeps its touch input and outcome identity within that page or composite instance. Keys must be unique in that scope and be nonempty strings/symbols, finite numbers, or booleans. A model expression cannot be a key. Arrows without keys retain their existing path-and-label identity.

Undo and redo

Undo is opt-in per arrow, because the model is shared: restoring a value can overwrite someone else's later change. Mark an arrow undoable and the open view offers it on an Undo/Redo bar and on Ctrl/Cmd+Z, Shift+Ctrl/Cmd+Z and Ctrl+Y. Text fields keep their own undo.

STATE decision = "pending"
STATE approvals = 0
 
SURFACE Review
  "Approve" ->
    decision = "approved"
    approvals += 1
    undoable
END

The runtime reports what the click actually committed, and undo reverses that:

  • A value written only with += or -= moves back by its own amount, so other people's changes to it survive.
  • Any other value (=, ?=, *=, /=) is restored. If someone has changed it since, the Undo button says whose change it would overwrite.
  • Table mutations (table T += …, ^=, *= by id, -= by id) restore the rows they touched. A where form offers no undo for that click.

Effects such as HTTP calls cannot be taken back once they run. Either hold them so an undo can cancel them first, or say how to reverse them:

input amount = 20
STATE sent = FALSE
 
SURFACE Payments
  "Send reminder" ->
    sent = TRUE
    HTTP_JSON("https://example.test/remind", amount)
    undoable within 10s
 
  "Charge" ->
    HTTP_JSON("https://example.test/charge", amount)
    undo -> HTTP_JSON("https://example.test/refund", amount)
END

undoable within <duration> (up to 10min) commits the values at once and holds the effects: an undo inside the window cancels them, and after it they run. undo -> … declares the reversal; it runs on undo with the values of the original click, unless held effects were cancelled instead. Redo runs the arrow again for either form. History belongs to the open view: it holds 50 steps, a reload clears it, and other viewers never see it.

CHECK "description" blocks retain isolated interaction checks for tooling and are not rendered. Syntax errors recover at outline lines so later siblings remain available to the editor.

Code completion offers standard and imported element names, the phrases their contracts declare, and closed property choices. The compiler supplies exact replacement locations, including unfinished view lines; comments and embedded JavaScript/CSS remain outside these Grid suggestions.

Create and convert in Code

Choose New Grid View in the surface explorer or the model Code toolbar. Name the View, then choose Add to source draft. Whole model opens before insertion. The starter includes a page, an editable greeting, and an isolated interaction check. Existing model source is preserved; the compiler selects the insertion point, including inside an explicit MODEL block. The rich Code editor records the addition as one Undo step and keeps Whole model open with the new View's inspector. Try creating Preview, use Code Undo to remove the addition, and Redo to restore it. Save in Code when ready to apply the new declaration; creation pauses source autosync until that explicit Save. The plain editor fallback can still stage a View, with its existing limited editor commands.

For an existing App, choose Convert to Grid View in its Code surface toolbar. Apply or discard pending surface-file changes first. Review the candidate source, compiler feedback, translation notes, and document differences. The conversion keeps the original App and opens a separately named View in Whole model. In the rich Code editor, the reviewed source is one Undo step, preserving earlier history. The View's inspector appears when the compiler recognizes its declaration. If Code is still loading, Cancel conversion stops the pending insertion. A candidate with gaps can still be opened for correction. Source autosync is paused until an explicit Save. Changes to the App, model source, partition or installed dependency environment before insertion require a fresh conversion; an editor refusal never retries the insertion automatically.

With the canonical examples/canonical/grid-view-component-migration.json App, review the component mappings, open the draft, then use Code Undo and Redo before saving. The original App source and the generated component declarations stay separate. The plain editor retains direct staging and its limited commands.

The source outline displays the authored hierarchy beside the preview. Selecting an item reveals its source and available Properties. Edit literal text, labels, page titles and paths, button captions, and unavailable reasons. For supported declarations, the inspector also groups bindings, visibility and availability conditions, row sources, actions, and named-region arrangements. While a text or expression property update is pending, Cancel update keeps the entered field draft and prevents the pending result from applying. You can retry immediately. Cancel does not reverse an update already applied; use Code Undo for that. Changed field contracts or withdrawn host editing support retire pending updates automatically. Component options, reusable arguments, event handlers, slots and availability requirements offer Cancel option update with the same retained-draft behavior. If an imported contract changes its fields or limits, obsolete drafts and pending requests are retired even when its contract name is unchanged. Record defaults, field additions, renames and removals offer Cancel record update. The pending source edit is canceled while the entered default, field name and new-field draft remain available for retry. Equivalent analysis refreshes keep these drafts; a changed record declaration contract clears obsolete edits.

Update source applies the selected property as one editor undo step; normal Code saving applies the declaration to the model. Selecting an element in the accepted preview opens its matching outline item and available fields. Selecting a generated record-form field also selects its matching default in Record fields, including nested paths. This works in Inspect copy as well. If a nested field comes from a computed or referenced default, selecting it opens the containing default expression supplied by the compiler. Properties identifies the preview field and explains that editing the expression changes the whole nested default. The inspector requires one matching compiler-owned record and expression; computed root schemas or ambiguous owners retain their existing source guidance. The nested defaults example shows an address selected from two named records. These controls edit source defaults, not the field's current runtime value.

Explicit standard elements and native components declared with ELEMENT ... FROM also expose an options panel, as do embedded views such as Calendar, Map and Kanban. Existing properties appear first; Add property lists the remaining contract-supported properties. Numbers use bounded numeric fields, closed choices use dropdowns, and boolean options use Yes/No. Choose Expression or binding for a dynamic value; input/read binding slots use that mode directly. Text values are quoted by the compiler, so quotes and line breaks do not need manual escaping.

Automatic standard controls show the chosen type in the panel heading. Bare placements such as qty AS "How many?" offer shared options such as help, size, spacing and width while keeping automatic type selection. For a direct binding, Use Slider (or the current component type) writes an explicit component use and exposes its full options. This is a deliberate choice to pin the component type, with one undo step; later model type changes no longer choose a different component for that placement. The binding, label, guard, comments and model-owned validation stay intact. show and edit placements offer this explicit-type action where supported. In examples/canonical/grid-view-order.grid, select qty AS "How many?", choose Use Slider, then edit its step or other options. Custom PRESENT controls use the same panel. Shared options remain automatic; Use [component] pins a caller-visible local or imported component and opens its argument or native property controls. The compiler retains the effective label, binding, guards, body and required model access. This is a source change, so the preview refreshes and component-local draft state may restart. A component private to its library offers shared options with an explanation; the inspector does not expose a private name as a caller invocation.

Automatic tables and maps also expose shared options. Use Table preserves columns, filters, paging and matrix headers, then opens the table settings. Columns whose names could be mistaken for settings, such as empty or rows, gain an explicit show prefix in the same Undo step. Use Map opens the embedded map configuration, including basemap and zoom, while retaining its data binding, label and visibility condition. Direct bindings offer these actions; literal and computed placements retain their existing admission semantics.

Generated record forms expose shared options while keeping their generated fields and Save action. For an edit Profile placement, Edit form options uses the equivalent automatic Profile spelling before opening those controls. Record fields lists the source defaults of an input or local object literal, including nested fields. Select a field to open its exact source or change its default expression. The compiler checks the edit, preserves the other fields and validation, and applies one Code Undo step. Plain aliases lead to their input; component-local defaults belong to the shared definition, while each instance keeps its own state. These source edits do not write the current live record. Local defaults must be literal values. Sensitive defaults stay in Code, and computed or indirect schemas link back to the owning declaration.

Use Add field to choose a parent record, name and default. An object default, such as {city: ""}, creates a nested record. Empty records can receive their first field here. Select a field or nested record to rename or remove it; removing a nested record removes its children together. These operations update the owning declaration and generated form in one Code Undo step, retaining surrounding comments and the other field values. Parenthesized default expressions retain their source spelling. Names are stored record keys: references elsewhere keep their old spelling and may need changes in Code. This is a source-schema edit, not a migration of already stored record values.

Whole-record VALIDATE and individual model-input field rules can coexist:

input Order = {amount: 2, city: "London"} VALIDATE <> BLANK
VALIDATE FIELD Order.amount > 0 MESSAGE "Enter a positive amount"
VALIDATE FIELD Order.city <> "" MESSAGE "Enter a city"

The generated Form saves the record as one input. Native validation checks the whole record and its field rules against that proposed write; the fields do not become independent inputs. Field failures appear at their exact paths, with a summary for errors that have no matching control. Whole-record failures stay at Form level. Save checks the contract again even if no Check values action was run, and a refused save retains the draft for correction.

When model field rules are present, the schema controls refuse rename and removal and offer links to their declarations in Code. This is conservative: the links include all model field rules because target aliases and operand references have not been proved for schema refactoring. Additions and default edits remain available. Review a coordinated schema/rule edit in Code rather than leaving a rule against an old stored key. Private-local field contracts and table-row contracts remain separate future work. See the field-rule reference for exact-key syntax, ownership limits and the remaining development verification. The record-field example combines an alias target, a live bound and a whole-record rule; its source is also used by the native proposed-batch regression test. The inventory is bounded to 256 leaf defaults and 256 schema members per record, 32 path levels, 64 KiB per expression, 16,384 field/container/rule-link associations and 512 KiB of field and path text across an analysis. New names accept up to 1 KiB without quotes, backslashes or control characters. Large records or unsupported source layouts explain the Code editing boundary. The automatic controls example demonstrates a record form, a table with named columns and a map.

When converting an existing App to a View in Code, the review includes a Page mapping table. It shows each original page name, its name in Code, route, starting-page status and old/new position. Choose Show source to select that page in the candidate without changing your draft. The starting page appears first because View page order selects its starting page. Invalid names and names that differ only by case receive distinct aliases; valid names are reserved before aliases are chosen. Buttons use the same names as the generated pages. Renaming and reordering stay visible in the document comparison, and duplicate routes remain an explicit migration gap.

The page-migration App document shows a quote page with a non-Grid name, an existing Page_1, and two order pages whose IDs differ only by case. The last page is home. Conversion produces Page_3, Page_2, Page_1, then Orders; the page table retains their original identities and positions. The buttons reach the new order, quote and home pages, including an uppercase route with surrounding slashes. The original App remains available while you review and save the candidate.

The Component mapping table reviews each App library component's original name and library ID, its Code declaration name, and whether source was generated. Names with spaces, View keywords, standard-control names and conflicts with other components or the receiving model get distinct Component_N names. Existing valid names are reserved first. Show source selects the complete declaration; unsupported templates remain listed with their translation notes.

The component-migration App document includes a “Résumé card,” a Card, an existing Component_1, and two names differing only by case. Convert it as Desk in a model declaring input Price = 3 to also see model and View-name conflicts. Review the mappings, open a declaration, then stage the candidate in Code. Library IDs, versions and descriptions survive in source annotations; exporting later uses the current Code declaration name. The original App and remaining document differences stay available for review.

The selected App migration operation retains portable component-library templates as ELEMENT declarations. The compiler also exposes a portable component bridge for standard nodes with concrete App binding parameter types, named content slots and default content. Exported templates pass the normal App component package validator and can be instantiated with new bindings and body content. Local state, captured model bindings, runtime glue and unsupported properties require an explicit mapping; the bridge refuses them. Original template node identities remain a reported migration difference.

In Code, choose Export component, select a top-level ELEMENT and set each parameter to Any value, Number, Text, Boolean, or Range or table. Prepare component checks the complete current draft using the model’s installed imports. Review the parameters and named content slots, then Download .gridui. Import that file through the App Builder’s component library and bind its parameters to the receiving model. A draft containing only reusable elements also supports this flow; it does not need a SURFACE or a source save first. Changing the draft, model, partition, imports, or parameter choices discards the prepared file. Compiler refusals appear in the dialog and leave source intact. The reusable amount editor is a complete example: export Editor with amount set to Number.

To bring an App package directly into Code, choose Import component. Open its .gridui file, select one component, and choose Name in Code. Review component source checks it against this model’s current draft and installed imports. Review the generated ELEMENT declaration, then choose Add to source draft. Code opens Whole model, pauses automatic source deployment, and adds the declaration before END MODEL (or at the end of an unwrapped model). Use it from a View’s Add element controls. Import is one Undo step; Save applies it.

The package must be version 1, at most 1 MiB, and contain 1–256 components. Names use letters, digits or underscores, start with a letter or underscore, and have at most 80 characters. Choose a different name if a component, function, model binding or namespace already uses it. Changing source, model, partition, imports or the chosen name invalidates the review. Unsupported templates fail without inserting partial source.

Import preserves the component’s library ID, tier, version, description, parameter labels/types/defaults and slot labels in a # @grid-component-v1 JSON comment directly beneath its ELEMENT header. Keep that comment with the definition. It is bounded to 64 KiB; individual text fields accept up to 16 KiB. Export component starts with those parameter types and shows the retained version, description, labels and defaults in its review. Changing a type still runs the compiler’s normal component checks. Renaming a parameter or slot requires updating its metadata before export; malformed or duplicate annotations refuse export instead of silently dropping details. Code marks these metadata problems as warnings at the source annotation.

This metadata is for App reuse. It does not change Grid formulas, argument arity or default values: Grid callers still supply each argument. App library import assigns its own local ID; the downloaded definition retains the source-owned ID. Template node IDs are regenerated. The estimate card demonstrates version 3, an App default binding and a labeled body slot. Export it, import it into another model’s Code and prepare it again to review those details.

For an element with local state or model actions, choose Grid source component (.gridcomponent) as the package type in Export component. Review its source and parameter types before downloading it. The stateful counter example has two instances with separate drafts and an Apply action that writes the receiving model's explicit amount argument.

Open a .gridcomponent file through Import component, review its source, and add it to the draft. Place it in a View and Save to compile its locals and rules in that model. App Builder also accepts source packages through Import View component…, with binding review and separate source/App saves. Portable .gridui templates remain available through the component library. Export and import do not execute the component or copy model values, compiled rules, live state, or trust approvals.

A version 1 source package contains one top-level ELEMENT, its name and concrete parameter types, within 1 MiB. Export includes the local element and named action helpers it uses, including helpers used by other helpers, action callbacks passed to local elements, and custom PRESENT controls. They appear as nested declarations inside the exported component, preserving existing nested overrides and keeping receiving-model helpers separate. The import review lists their names; review their source before saving. Pass model reads and write targets as parameters. Captured bindings, model-relative references and calls whose standalone dependencies cannot be established remain refused. A named action is invoked from an action body; it does not become a function for ordinary formulas. Shared Grid functions and imported dependencies still belong in a Grid library.

The component helpers example splits a counter across DraftField, ApplyControls and CounterFields. Export Counter as a Grid source component with amount set to Number. Import it as QuoteCounter or create a complete View with amount bound to the receiving Estimate input. The review includes all three helpers. Two instances keep independent drafts, and Apply writes only the chosen instance's value. The named action example exports ActionCounter with bumpDraft, writeAmount and applyAmount nested inside it. DraftControls receives the Apply action as a callback. Export with amount set to Number, import with an explicit receiving-model binding, and review the named action list before saving. Bumping one draft leaves the other unchanged; Apply sends only the chosen draft to the bound input.

Helper source and captured bindings are checked again in the receiving model. Import also checks the receiving context: if a bare caption would turn into a binding there, quote it before exporting. Embedded payload bytes stay intact; normal View trust and library requirements still apply. Changing package type or host support retires the prepared review.

To create a complete View during import, select Create a View instance, enter its View name, and supply each parameter's model binding. For the counter, choose CounterView and bind amount to Estimate. Review the generated element and SURFACE together before Add to source draft. Both are one Undo step; Save compiles the new View. Repeat with a different View name to create another instance with separate local state and action rules. Bindings must be declared model names or cell/range references; formulas and literal values are not binding arguments. The compiler refuses missing/extra parameters and occupied names. After saving, choose Insert View… in App Builder, select the saved View and review its bindings before insertion. You can also choose Import View component… directly in Builder: open the source package, name its View, choose bindings and review source, then Save and insert. Source and App placement are saved separately. Failed placement retains an App draft for recovery; Undo removes the placement and leaves the reusable View in Code.

Place the same saved View twice to give each placement independent local edits. Labels, help, validation messages, page headings and tab panels address their own rendered instance. Controls retain those associations through value updates and keyed row reordering. Both placements still share the model bindings you chose; create separately bound Views when different model inputs are required. To try it, save the source component example, insert its Estimates View twice, and use the Draft fields and Bump actions in each placement. Code selection and source navigation continue to identify the shared declaration.

A composite declares BODY "heading" where named content belongs. Its indented children are defaults. At the use site, SLOT "heading" supplies replacement children; an empty SLOT "heading" suppresses the defaults. Bare BODY receives unnamed caller children (or an explicit SLOT "body"). Defaults resolve in the component’s scope, while supplied content resolves in the caller’s scope. Names are case-insensitive in Grid, with the original declaration spelling retained in App exports. Fill each slot once; put conditional content inside the slot rather than guarding the slot header. Names accept up to 256 UTF-8 bytes without control characters, with at most 64 BODY placements per component.

The named-slot card demonstrates an overridden heading, unnamed body content and a default footer. Export ReviewCard with amount set to Number. In another model, use Code’s Import component, name it EstimateCard, review and add it, then insert EstimateCard in a View and bind amount to an input. You can also try Undo immediately after import to remove the declaration. App imports preserve the slot names and default children; inserted content keeps its own bindings. Select a composite in Code to add, update or remove its declared slot fills through Add property, event or slot. Removing a fill restores its defaults. Bare BODY also offers the Content editor. Completion supplies the exact SLOT headers. Portable App export retains each slot’s Stack container settings. For example, BODY "heading" padding 12 gap 4 class :heading keeps that layout when callers replace the content. Use an explicit quoted name, including "body", before container phrases. View runtime behavior still needs an explicit mapping.

An explicit composite with labels or layout settings uses a closed argument list, for example OrderSummary("Order total", total) AS "Summary" help "Details". Following shared property lines belong to that component; a blank line starts caller body content. Arguments named width, size or other phrase words stay arguments inside the parentheses. Bare argument expressions retain their existing meaning. The reusable arguments example includes both this spelling and a custom automatic quantity editor.

Direct model input bindings also show Input validation, owned by the named or cell-address input declaration. Choose Open input declaration to open Whole model while keeping the View inspector beside it. Enter the clause after VALIDATE, such as BETWEEN 1 AND 10 MESSAGE "Choose 1–10", then add, update or remove validation. The change shares Code's undo history and applies everywhere the input is used. For the order example, select qty AS "How many?", open its input declaration, and change the validation clause to BETWEEN 1 AND 20. The declaration keeps its existing default, type and presentation settings. Automatic controls may choose a different presentation when their input contract changes.

These controls follow direct named inputs, including qualified names and supported native main bindings, and direct A1/R1C1 cell inputs. Plain aliases also lead back to the input; the panel names the alias and the declaration it owns. Calculations, typed or lazy bindings, cycles, and aliases with their own validation do not authorize this shortcut. Cell-address controls keep the input's validation, format and preferred presentation.

Select a table, picker or one of its columns to open Table columns. The selector lists display columns, editable fields and row actions in source order. Add a column, change its value or heading, set a literal FORMAT, alignment, width, remove it, or move it between neighboring editable columns or row actions. Display columns also offer Text/Badge/Metric presentation; editable fields keep their input control. Each change uses one checked Code transaction and selects the resulting column. Attached comments move with their column; filters, paging and table empty messages keep their source. Complex column settings retain an Open column in Code action.

Add row action creates a button caption and a Grid action, such as SelectedRequest = row.id. An optional unique action key keeps its identity through caption changes and moves. Select an existing unkeyed action to add its key from the same field, then choose Update row action. The compiler checks uniqueness before applying the change in one Code Undo step. Existing explicit keys remain in the source header; changing them deliberately stays in Code. Use semicolons between inline steps; open nested steps from the outline to edit their source. The selected row action also exposes Action requirements, with paired conditions and explanations. Updating a caption or inline body preserves nested steps, visibility, requirements and refusal handlers. Moving or removing an action carries its whole block, including an attached sibling ELSE. The compiler checks row-field references and model writes before changing source. Nonliteral captions retain their source editing explanation and navigation.

With no explicit columns, the table shows all source fields. Adding the first column or row action starts an explicit list; removing the last returns to all fields. Use row.amount for an explicit row read or a computed value such as row.amount * 2. Editable cells instead takes a plain field name and requires an admitted keyed array/table source. It retains the heading, literal format, alignment and width; for example edit amount FORMAT "$#,##0.00" AS "Amount". The compiler refuses computed or unwritable row targets. Formatted fields show native display text while resting and unrounded values in display units while editing. An untouched blur makes no write. Enter saves and Escape cancels; failed saves keep the draft with a retry. A concurrent value change keeps the draft and requires Reapply my value before overwriting it. Sorting retains the draft by row key. Leave the Format field empty to inherit the model's FORMAT <tag> policies. The native formatter selects the most specific policy from each field's actual value tag, falling back through its tag ancestors. Reactive policy changes refresh the display without reinterpreting an active draft; an explicit column pattern takes priority. A blank policy inherits its ancestor. Pending, invalid or failed policies explain the problem instead of displaying an earlier policy as current. Exact numeric strings keep their text under inherited numeric policies. The inherited row formats example shows a reactive number policy, currency and percent fields, editable cells and an explicit override.

Declared field tags also survive plain JSON replacements and browser-local rows. The compiler retains tags shared by every literal row. Conditional records and row sets keep only tags shared by both outcomes; IFERROR/IFNA fallbacks must agree too. Whole-row FILTER, SORT, SORTBY, TAKE, DROP and UNIQUE operations keep these hints. A FILTER fallback must have the same hints. Column transformations, disagreeing branches and unknown schemas do not acquire an invented common tag. A live refined tag takes precedence over the declaration hint. The same metadata selects generated record controls, including nested local records. Record fields inherit model formats; numeric fields keep their editing units in a staged Form draft. Dates, date-times, text and checkboxes show a formatted readout beside the original editable value. Date controls keep civil dates, and zoned date-times retain their supplied offset. An ISO-looking text field remains text. Save still commits the record once; formatting does not rewrite its values. The parent record's own format does not leak into individual fields. These scalar controls remain editable while formatting loads or retries; print uses the selected formatted text. A policy with no match retains the normal display. Exact numeric text and structured editors retain their existing presentation. Currency, percent and unit literals in local defaults use the native literal lowerer; decimal and bigint defaults preserve their exact text. The field formats example combines a reactive currency policy, a nested record Form and private local rows. The computed field formats example uses a conditional invoice default and a selected row list. Generated controls keep currency, percentage and date presentation. The Form stages raw field values and saves one checked input; changing a column format in Code overrides its inherited policy, and removing it restores inheritance. Declared date/datetime row values use the native formatter's temporal carrier, including plain JSON replacements. Ordinary date-looking text stays text; live refined tags and resident table schemas take precedence over declaration hints.

Resident model tables and table views use the current handle's column type and unit. Currency columns select their concrete currency policy, percent columns select percentage policies, physical units use the native tag hierarchy, and date/datetime columns retain date formatting. An explicit column format still wins. Schema changes refresh the display; active drafts keep their editing units. Blank numeric columns retain numeric entry and the keyed native write. Only requested pages cross the table binding boundary; format selection reads no model data. The native table example uses an existing Ledger table and explains the required schema.

Per-row local hints for mixed/computed schemas still need integration.

Plain eager aliases, including chains to named or cell-address inputs/defaults, retain keyed editing at the owning declaration. The runtime reads and rewrites that owner in one commit; the browser sends only the selected key and new value. Native table aliases keep their keyed update. Calculated, typed, lazy or cyclic aliases and aliases with their own validation assertion do not gain this write access. A local that shadows a model input does not become a model row lens.

A model record can own the editable list: Table Order.shipping.lines updates that stored list inside the Order input/default. Plain aliases to Order work too. The generated rule reads the current order and replaces only the selected row field, preserving parent fields, neighboring rows and native field values. Scalar and record/list editors, sorting and acknowledgements use the same controls. The shipping lines example shows both kinds of edit.

Code's column Properties edits these declarations, and Row source validation opens the containing input's whole-value rule. It keeps navigation to the displayed row expression separate from navigation to the input declaration. Repeated readouts over the same stored path inherit that contract context. It is not a contract on each row or field. Dynamic field keys, dotted INDEX fallback keys, calculated collection aliases remain outside this write contract.

A table can also edit a list inside an enclosing model row:

SURFACE Desk
  FOR order IN Orders key order.id
    Table order.lines
      edit amount
END

Each enclosing repeater needs an explicit stored-field key, such as order.id or batch.code. Nested rows and reusable elements retain those keys; the final table rows need id. The initial records must establish common fields across all parents. Up to 32 stored-field/key steps are admitted. The nested orders example includes two enclosing lists and scalar/record editors in a shared element. Edits read the current owning input and retain neighboring rows and parent fields. Missing or duplicate keys reject the whole edit with an explanation. Drafts stay with their keyed parents through reordering; changed fields require explicit reapplication. Nested edits use the updated native host's guarded View action. Code's shared table definition offers the same column controls and containing input validation; those changes share Code Undo.

A declared local array can also use edit amount. The compiler keeps this edit private to the open View, including Table draft.lines inside a local record and lists owned by repeated elements. The initial records establish the editable fields and stable id key. Numeric and text keys remain distinct. Edits find the current row by its key, preserve other fields and records, and check the whole local declaration's validation before saving. Removed rows, missing/duplicate keys and conflicting values keep the draft with an explanation. A changed field requires Reapply my value; it cannot silently overwrite a newer value.

Private table columns also support record and list fields. Choose Edit record or Edit list, change the JSON value, then Save value (or Command/Ctrl+Enter). Cancel or Escape discards the draft; leaving the field does not save it. Use null to clear a field. Initial array/record hints retain the appropriate editor for blank fields. Save replaces only that field at its current row key; newer neighboring fields and other rows survive. A conflict retains your draft, shows the current value and requires Reapply my value. Failed saves retain the draft for another attempt. An unchanged save writes nothing.

The editor accepts plain JSON up to 64 KiB, 4,096 values and 32 nested levels. Keep integers beyond 9,007,199,254,740,991 as text. Nested lists retain their shape, including lists of pairs; records with kind or value fields remain records. This edits literal data, not formulas. Whole-local validation still applies; individual field contracts remain incomplete. The catalog draft example shows record/list edits, blank repair and reset. Column Properties uses the same checked edit source declaration and Code Undo as scalar columns.

Model-backed input/default record lists support the same editor for stored record/list columns, including through plain aliases. Existing native field and list-position types are retained: currencies keep their units, dates and exact numbers keep their text, and matrices keep their axes. Retained value types shows up to 32 tagged paths. Native type changes also cause a conflict, even when the displayed JSON is unchanged. Reapplying uses the types from when the draft was opened. Use Code to change an existing value's type. New fields and list positions become literal Grid values; null clears a value.

A save sends the typed row key and field value through the existing generated model action and waits for its outcome. It does not replace the displayed row. The model catalog example shows a currency inside a record and a list of pairs. The editor bounds include the native representation as well as the visible JSON. Native record carriers are required for rows; opaque JSON rows, resident table blobs and unsupported native field kinds retain an explanation and source editing. Full native-host journey validation remains pending.

Sorting, paging, native formats, print and the column Properties editor use the same controls as model tables. Reset restores the local's default, and closing the View discards its private changes. The private estimates example combines a nested local picker with independent repeated estimate lists. Nested tables can follow keyed enclosing rows back to the same private local. For example, FOR order IN orders key order.id can contain a Table order.lines with edit amount. Further keyed levels and stored record paths work too, including rows passed to reusable elements. Each enclosing list needs an explicit stored-field key. The initial records must establish the editable column across all nonempty instances. The private orders example edits line items through order and batch keys; reordering either level preserves ownership. A removed or duplicate ancestor refuses the edit. Literal dotted field names that conflict with a nested path must be renamed before editing. Whole-local validation and reset still belong to the original local declaration.

Computed JavaScript collections, bare literals, native slot values and nested model collections still have no admitted private local write owner. Column Properties edits a caller-owned nested table; shared element definitions remain authored in Code.

Tables, pickers, columns, row actions and controls inside a repeater also expose Row source validation. This is the contract on the whole surrounding collection, not a separate rule for each row or field. Open row source in Code selects the authored collection expression; Open input declaration or Open local declaration selects the declaration that owns its contract. Plain aliases lead to their admitted owner, and a View local takes precedence over a same-named model input. Nested tables and repeaters use their nearest row source. A private collection such as draft.orders, or order.lines inside a repeat, also links to its containing local declaration. Properties explains that the rule validates the entire local, including its other fields and lists. This works for read-only collections too; it does not require an inline row-edit lens. Repeated body locals retain their exact declaration even when an outer local has the same name. Try the nested validation example: select Amount, open its row expression or the draft declaration, then change the whole-draft rule through Code Undo.

A picker retains separate owners for its selected value and its rows. A repeated control bound to another input also keeps that input's own contract. Choose Validation owner to switch between them. Updating or removing the row-source clause changes only the owning declaration, through one Code Undo step. In examples/canonical/grid-view-columns.grid, select edit amount or the repeated Metric to find Requests; select the picker itself to also inspect SelectedRequest. The picker's RequestRows alias keeps edits and validation at Requests; the source navigation button selects the alias expression. The example's <> BLANK requires a supplied value; it does not require a nonempty array.

Computed collections and native table expressions without a direct editable input/local owner offer source navigation and an explanation. The inspector does not guess an upstream input or treat a native table handle's declaration contract as validation of stored rows. If the authoring inventory limit is reached, source navigation remains available and additional row-source edits are withheld. Computed JavaScript collections and foreign or ambiguous origins do not borrow a containing declaration's contract. Admitted stored column names remain row fields in Code even when the schema is known only at runtime. Individual table-row contracts remain outstanding; this row-source editor changes the whole input or local declaration's VALIDATE clause. Model-input record members may separately use VALIDATE FIELD. That syntax does not grant validation authority over array elements, resident table rows or private-local fields.

Local collections can also supply tables and repeated controls. For example, FOR request IN requests key request.id reads a stored ID from a View-local array without creating a model calculation. Nested collections such as FOR line IN request.lines key line.id read the enclosing row. Dotted local collections, literal arrays and empty arrays use the same renderer and paging; empty lists display their ELSE sentence. Stable keys retain a row's Form drafts when the collection is reordered.

A sibling ELSE block immediately after a repeated button handles a refused action for that row. It retains the row's values and outcome.message; it does not run the successful follow-up actions. ELSE "No requests." remains the list's empty-state sentence. The same sibling handler form works for named native-control events, and editing or removing an event in Properties includes its whole refusal block while leaving adjacent events and body content intact. Try the request refusal example: choosing Northwind leaves the selection unchanged and reports its review requirement; choosing Contoso succeeds. All state stays in the open View.

Try the private shortlist example. Choose a customer, clear the list, and restore its default. In Properties, change Row identity to another stored field through a checked source edit and Undo. These actions affect the open View's locals. They do not write a model array. Locals declared in a repeated component or directly inside a FOR body belong to that element path and row key. Reordering, paging away or temporarily removing a row keeps its draft; restoring the same key restores that state. A different key starts from the declared default. Closing and reopening the View resets all locals. Inputs, actions, reset and validation use the same row-owned value; View-wide locals remain shared within the open View.

Try the private row drafts example. Increase Ada's quantity, hide the requests, then restore them. Only Ada retains the changed quantity. Select RequestDraft request.customer in Properties to edit the shared validation declaration with Code Undo. A local declared directly inside the repeater likewise edits its own declaration, even if an outer local has the same name. Private-copy setup lists View-wide values; edit individual row drafts in the preview and their shared defaults or validation in Properties.

Stateful repetitions require a key, including ancestors of nested stateful repetitions. Keys may be text, finite numbers or booleans; numeric 1 and text "1" are distinct. Missing or duplicate keys show an error at the repeater, without combining drafts. Native handles rely on the host's stable row identity; array keys are checked across the complete collection, including other pages.

Browser rows support stored fields and direct field keys. Grid calculations, computed keys and FOR … IF over browser-local data are refused with GRID_VIEW_NOT_STAGEABLE. Use an explicit JavaScript row source to filter or compute its fields first, or use a model collection for Grid expressions. Inline JavaScript and named SCRIPT exports can provide an array or record immediately; USING retains explicit model reads. Use row.amount when a SCRIPT source has no inferred schema and amount also names a model value. A Promise or invalid scalar result reports an error at the row source. Ordinary model row calculations keep the native path. This does not add local-array inline editing.

Width accepts a literal such as 140 or "12rem". Literal column FORMAT patterns use Grid's native TEXT formatter in previews and published Views, including decimal places, grouping, percentages, negative sections, scientific notation and dates. Sorting, selection and inline edits keep the original values. An unavailable host or failed batch shows a concrete explanation and unformatted values; Retry formatting retries the display operation. Stale responses cannot replace a newer page. Print/PDF waits for the displayed formats and asks you to resolve failures before capture. Patterns support up to 256 UTF-8 bytes and scalar text up to 16 KiB; larger values need a shorter display expression. See the formatted statement example.

Text, Metric, Stat and Badge values also honor declared FORMAT patterns and host-resolved tag or cell format policies through the native formatter. An explicit format choice on the control wins; otherwise the current host metadata wins over the declaration hint. View-local patterns work in private copies too. For example, Balance = -25 FORMAT "0.00;(0.00)" displays (25.00) in an inferred Metric. Dates retain their native scalar kind, and declared unit labels remain visible.

Scalar displays share bounded requests, show a fallback with recovery guidance when formatting is unavailable, and participate in print/PDF and HTML readiness. Changing a value, pattern, host or preview cancels its old display result. Scalar controls with no format pattern create no formatting request. Full native-host acceptance and row-field policy propagation remain separate work.

Numeric inputs also use the native pattern and the same precedence. At rest, they show the formatted value; focusing exposes the unrounded number in display units. Leaving without a change never writes a rounded value. Native section selection supplies decimal precision, percent/thousands scaling and locale separators, including quoted literals that look like formatting instructions. Sliders project bounds and steps into those units and write model units. An active draft retains its editing units if the pattern or host changes.

Plain decimal or scientific input is accepted in the active format's units. Numeric controls and editable table cells also accept the native pattern's prefixes and suffixes across sections, including $12.50, ($12.50), localized percentages and scaled values such as 1.25K. Fraction patterns accept 1 1/2, 3/2, negative fractions and their unit labels. A fixed display denominator does not restrict entry: entering 3/8 under a sixteenths pattern stores 0.375. Focusing still exposes the unrounded decimal, and untouched blur never writes.

Try the workshop quote: enter 2 3/16 as the cut length and paste ($15.75) into a positive charge. The private line table uses the same entry behavior. In Properties, change the Length column's format to # ?/?, then Undo the source change.

Invalid grouping, zero denominators, unsafe fraction integers and ambiguous signs or scales retain the draft with an explanation. For example, a pattern that uses the same decoration for both signs cannot recover the sign from pasted text; enter a signed decimal instead. Form Save stays disabled until an invalid field is repaired. New host or format responses cannot reinterpret an active draft. Plain decimals always use that draft's current display units.

Exact decimal/bigint strings retain their separate text path. Date/time formats, literal-only sections and text embedded between numeric digits do not gain a numeric inverse; their existing controls remain in effect. Older hosts retain their current-section decimal entry. If the host cannot provide a valid editing plan, the control explains the failure and offers basic editing plus Retry formatting. Pending plans block new numeric edits; retries and late results cannot replace an active draft.

The editor supports up to 256 columns within the shared analysis budget; larger lists remain in Code. Source changes, selection changes or unavailable host tools cancel pending edits. Inline region tables expand in the same Undo transaction when needed.

Open examples/canonical/grid-view-columns.grid, select its Requests picker, change the Customer heading to Account, move the display columns, and undo. The edit amount column retains its keyed model write and the Choose action continues to select row.id.

A local declared directly inside a View shows Local state validation when you select its declaration or a directly bound control. Open local declaration locates its source. Each open View keeps its own state; editing this declaration does not change a same-named model input. Local validation accepts literal values, not model references. Defaults, sensitive, comments, FORMAT and PRESENT remain intact, and edits share Code's undo history.

Select a reusable element to inspect the input or View-local contracts passed as plain arguments, along with locals in its definition and the helper components it uses. This includes nested definitions, transitive helpers, native slots and caller content consumed through BODY. Unused definitions and unconsumed caller content do not contribute local contracts. Choose a Validation owner when more than one declaration is involved. Component-local edits change the shared definition for every instance; each instance still keeps its own state. The panel opens that exact declaration before editing it outside the current source section. Imported component locals remain in their library's source, while caller-owned input arguments can still be edited here. Nested definition paths distinguish same-named helpers in the owner selector. Only compiler-admitted instances contribute owners; repeated instances of one definition share one entry. If the bounded inventory cannot include all nested owners, the inspector explains the limit and directs you to Code.

Open examples/canonical/grid-view-validation.grid to compare the shared Orders!B2 input, the private trialQuantity local and two QuantityPreview instances. Select the alias display to find the shared input. Select either QuantityPreview, choose draftQuantity (QuantityPreview local), change its validation to BETWEEN 1 AND 20, and undo the source change. Both instances use the definition's contract, while their drafts and the View's trial remain separate. Choose trialStep (QuantityPreview › DraftControls local) to edit the nested helper's contract or open its exact declaration.

Row lenses, complex indirect bindings and computed-cell assertions still require Code. A row edit updates its array/table field; a validation on the whole input is not a field-level rule. Ambiguous owners and unresolved or unsupported contract references cannot be applied through the panel.

For native components, the panel reads the admitted contract, including imported aliases such as Kit.Chooser and local phrasebook extensions. Fixed presets have an Add property or Remove property action without a value field. A preset such as spacing(size) presents its named arguments in order; enter 4 to apply spacing (4). Two-way properties request an input or local binding, and conditional properties explain the setting they require. Contract choices, argument counts, variant conditions and writable bindings are checked by the same compiler as Code. The inspector edits the caller's use site; the locked library stays intact.

Embedded view options follow the renderer contract. Column fields accept names such as Order title and quote them safely. Closed choices, such as Calendar's view and Map's basemap, use dropdowns. Fixed configuration values do not offer a dynamic expression switch; binding fields still accept model expressions. Array settings use constant Grid expressions—for example [45, -73] for Map's center. The compiler checks their types and refuses changing data in a fixed configuration field. Other settings stay in source.

Native components and embedded views also expose declared events in Add property or event. Select an event to edit its handler source; the field lists the values supplied by that event. For example, Kanban's on select handler can use card in on select -> selected = card.id. Keep the event name and edit its actions, key, guard or nested refusal actions, then choose Add event or Update event. Remove event removes that handler and its refusal actions. The compiler checks the event's scope and preserves neighboring settings, slots and events. Event changes share Code's undo history. This is a handler source field; it does not invoke the event.

Below component options, open a named event's requirements section to add, update or remove its individual conditions and explanations. The same controls appear when selecting the handler in the outline. Each event lists its own supplied values and keeps separate drafts. Open handler in Code reveals the exact declaration. Removing a requirement retains its nested action steps and refusal handlers; it does not remove the event. These controls cover native components and embedded views such as Kanban. Component header Availability remains separate. Try the ticket selection example: select the Kanban, open on select requirements, and edit the selection check or the card.id check. Each change shares Code's Undo history.

Declared native slots appear in Add property, event or slot. Select a slot to edit its content source, including its header and indented child elements. The field lists any values supplied by a scoped slot: for row(entry) holds renderRow, the row content can use Text entry.label. Choose Add slot, Update slot or Remove slot to apply one checked, undoable edit. The slot name stays fixed, and neighboring settings, events and other slots are preserved. An explicit body block uses these controls too. Components declaring body holds children also offer Content for child elements written without a slot header. Use Add content, Update content or Remove content; the compiler checks names in the caller's scope. If content is interleaved with properties or other slots, the field shows those content blocks in order. Updating gathers them at the first content location and preserves intervening settings, events and named slots. Attached comments and multiline payloads travel with their content. The operation is one undo step. A named body or alias prevents adding unnamed content over it, and existing unnamed content prevents adding a conflicting named body. If both forms are already present, resolve them in Code.

Direct native arrows such as Kit.Button label "Save" key :save -> save() also expose their header options. Additions go before key and ->; property updates preserve the action, guard, key and refusal handlers. On activation edits the inline actions and lists the event and supplied values selected by the component contract (onPress, with onClick as its fallback).

A separate Action requirements section adds, updates and removes body-level requirements. Component Availability stays in the options panel. For example, with Ready, HasChanges and save() declared in the caller's model:

# Keep the control visible with an explanation while preparation is incomplete.
Kit.Button label "Save" needs Ready ELSE "Prepare first." KEY :save -> save()
  needs HasChanges ELSE "There are no changes to save."

The header condition controls availability; the indented requirement is checked before the action runs. Each is edited in its own section. Action requirements can use values supplied by the selected activation event; those event values are not available to component header options. The panel lists the event values. Removing a requirement retains its nested action steps, other checks and refusal handlers. Other nested action steps remain in Code. Named handlers offer their own requirement controls in an ordinary component block; their complete action source remains editable through the handler field.

Selecting a caller-owned use of a reusable Grid element exposes an arguments and options panel with the parameter names from its definition. Choose Text, Number, Yes/No or Expression or binding, then Update argument. Text is quoted safely; bindings and named actions are checked in the caller's scope. Arguments are required, so the panel updates their values rather than adding or removing positions. Commas, call parentheses, guards, comments and caller content are preserved. Imported aliases use the same controls without changing the library. If an imported parameter changes identity, refresh analysis before editing. The canonical examples/canonical/grid-view-arguments.grid example uses OrderSummary("Order total", total): select that instance to edit heading as Text or amount as an expression or binding.

The Reusable component section identifies the shared definition behind the selected instance. Open component definition selects its declaration in Code; when it lives outside the current View, Whole model opens with the View inspector retained. A native component labels this section Component contract. Shared body or contract changes affect its instances; argument and option controls edit only the selected placement. In the canonical examples/canonical/grid-view-component-helpers.grid example, select either Counter(Estimate) and open the same ELEMENT Counter(amount) definition.

For an imported definition, the section names the owning library, including a private helper selected by PRESENT. Open import in Code selects the model's USE statement; Review component dependency opens the available dependency tools. Edit the shared definition in its owning library. These links require current analysis and preserve the caller's source when opening an import.

The same panel offers shared presentation options, including help, width, spacing and Availability. They apply to this placement without changing the element's definition. Argument names remain separate even when a parameter is named width or size. The canonical example includes width and availability controls.

Adding the first shared option encloses bare arguments in a call when needed. Caller content that resembles a property gains a blank separator to keep its meaning. Removing the last header option may move a remaining property from a continuation onto the header. Arguments, guards, comments and content remain intact; these source adjustments and the requested edit share one Undo step.

Add property, Update property and Remove property each produce one checked, undoable source edit. The compiler preserves neighboring phrases, comments, guards and child content, and refuses unknown choices, invalid literal ranges or unresolved expressions. Removing a property restores its declaration's normal default behavior. Native components expose their positional subject as Main binding or Main value, including add, update and remove controls. Two-way bindings require a writable input or local value; value contracts use their declared type. A named alias supplying the same property prevents adding a conflicting subject. Conflicting aliases, duplicate phrases or nested declarations stay in their existing source editors. Contract always settings are fixed by the component.

Availability edits a supported control's needs condition and explanation together. Enter a Grid expression in Available when and plain text in Unavailable explanation, then add or update the pair with one Undo step. The control remains visible when the condition is false and shows the explanation. This includes standard, automatic, embedded, admitted native and reusable Grid controls, with reusable arguments and shared options in the same panel.

Ordinary arrows and direct native arrows offer Action requirements. Each requirement has its own pair of fields, including requirements nested around other actions. Updates preserve neighboring requirements, action keys and refusal handlers. Use Add another requirement to append a condition and explanation after the existing checks. Remove requirement removes that check while keeping its nested actions and other requirements. Nested actions move up one indentation level; comments, multiline values and refusal handlers remain intact. Each change uses one Undo step. Cancel closes an unfinished addition. Adding a requirement to an inline region action expands its content and edits it in the same Undo step. See the availability example. Availability expresses readiness; it does not grant authorization to run an action.

To share availability across controls, select an element or container and choose Wrap in availability. Enter Available when and choose When unavailable: Show an explanation keeps the block visible with disabled controls and an explanation; Go to a page or View hides it and redirects when the condition fails. Enter the destination's declared name and any arguments. The compiler checks that destination. Create availability group wraps the selected block, its comments and attached refusal actions. Add or move more controls into the resulting group through the outline.

Select an existing needs block to change its condition, explanation or redirect with Update group. Remove wrapper, keep contents removes the availability or redirect and lifts its contents into the surrounding block. Arrange → Remove group and contents deletes the complete block instead. A separate visibility condition is retained when removing only the availability wrapper. Comments, multiline payloads, keys and refusal handlers remain intact. Inline regions expand automatically in the same Undo step. The canonical availability example groups its shipping and payment controls; select that group to try updating or removing its wrapper.

Wrapping or lifting a supported block that contains local, reusable or named-action declarations opens Review this group change. It shows the affected declarations and the exact before/after source. Apply reviewed group change applies that checked candidate in one Undo step; Cancel group change keeps the current source. A lifted declaration can become visible in the surrounding block, and a wrapped declaration can lose that visibility. The compiler refuses duplicate names, undefined references and invalid destinations. This does not move or migrate stored values. Condition-only updates keep the declaration scope and apply directly. Draft, selection or capability changes discard a pending review; Apply rechecks the current editor. Keep shared declarations at View level when only the placed controls should share availability. Reusable definition bodies, page-containing blocks and other unsupported source scopes stay in Code. Table row actions use their own requirement controls; a generic availability wrapper is not a table column. A control's presentation options do not replace its input contract; use Input validation for supported owners. A bare binding that shares a contract phrase's name can be parenthesized in Code to make the boundary explicit before editing it in the panel.

For complete source blocks, Arrange offers Move up, Move down, Duplicate, and Remove where supported. These actions include the element's contents and use one editor undo step. Consecutive leading comments at the same indentation travel with their element; a blank line separates unattached comments. Internal and trailing inline comments and original line endings are preserved. Use Move to to place an existing element inside another section, form or page, or after another element. The destination list excludes the selected subtree. Structural indentation changes; multiline literals and embedded JavaScript/CSS keep their exact contents. The compiler checks the resulting hierarchy and bindings before returning the undoable source change.

Moves across repeater, page or declaration scopes open Review this move. Review the current and destination scopes, declarations carried with the block, and the exact before/after source. Apply reviewed move applies that checked candidate in one Undo step; Cancel move leaves the draft unchanged. Names resolve at the destination: a valid same-spelling name may denote a different row or declaration there. Repetition, page action identities and component-local state may change with placement. Unknown references and invalid source still prevent the move. Changing the draft, selection, destination inventory or host support discards the review; Apply also checks the current model, partition, editor, version and edit permission. Moves within unchanged scopes keep the direct operation. Older hosts keep scope-changing moves in Code.

Try the request desk move example: move the repeated caption into Summary's Card, then Undo. A row-dependent field cannot follow it unless its row binding is valid at the destination. Pages use their own page controls; moving a block containing page definitions is refused. End of View appends after the last page in a paged View.

Pages can be reordered and removed with both nested content and flat placements following their headers. Shared View declarations stay in the source, including locals, reusable elements, named actions, scripts, styles, policies, themes, checks and next steps written between pages. Their source and relative order are preserved. Page order determines the starting page; removing the last named page leaves the View's shared content. A page still referenced by a link or check cannot be removed until those references are changed in Code. Select a page and change Page name in Properties, then choose Rename page. If needed, Open Whole model to rename page keeps that page selected while opening all source. The compiler updates local and qualified go destinations, NEXT links, route guards, and CHECK references to the page name. Existing titles, URLs and route parameters stay the same; inherited titles and paths become explicit AS and AT phrases. All replacements share one Code Undo step. A conflicting page name/title or a name that would redirect an existing link is refused. Shared definitions with unqualified destinations need a View qualifier first, such as go Orders!Review(selectedOrder); a foreign component whose navigation cannot be preserved needs a change in its defining library. Script text and external links are not rewritten. Save applies the renamed source.

Select a page and open Duplicate page to copy it with a new name and path. The suggested values are unused; overlapping routes, including parameterized routes, are refused. Both nested content and flat placements following the page header are copied after the original, along with attached comments and exact multiline payloads. The copy becomes the selected outline item and uses one Code undo step. Model bindings and navigation destinations remain unchanged; the copy gets its own page and action identities. Route parameters keep their bindings and order. Explicitly authored titles are preserved; otherwise the title derives from the new name.

In examples/canonical/grid-view-pages.grid, select PAGE Details(...) and choose Duplicate page. The suggested DetailsCopy at orders/:id/copy shares selectedOrder and submitted with the original, and its Review button still goes to the Review page. To create independent model data, change those bindings explicitly after copying. The example also declares reviewNote between pages: it remains a single shared local. Its flat Text placement belongs to Details and is copied with that page. Shared declarations, including their attached comments and exact embedded payloads, are never duplicated or deleted by page controls. To try a rename in the same example, select PAGE Review(...), open Whole model, and rename it to Approval. Its Review button now goes to Approval(selectedOrder); the displayed title remains Review order and its URL remains review/:id. Use Undo to restore the page name and every changed reference together.

Inline array members, branch alternatives, reusable definitions and embedded modules also remain in Code. Named layout regions have their own coordinated editor described above.

Use Find in View outline to locate existing elements by their name, kind or parent path, including inside collapsed sections. Selecting a result expands its ancestors and opens source and Properties. Results remain readable while analysis is stale, but source navigation waits for current analysis. The list shows up to 50 matches; narrow your search to find a particular element.

Use Add element or page to choose a placement: At View root, After selected element, or Inside selected element for supported containers. The compiler's standard control catalog supplies available elements and binding fields. Add labels, sections, displayed values, editable inputs, action buttons and pages. Input controls use an existing editable model input or local value. For a page, choose a name, title and optional path; the suggested name is unused, and conflicting names or paths are refused. New pages are appended using At View root, so existing placements keep their page. For other elements, the root choice appends to the source; in a paged View this follows the last page. Select a page and Inside selected element to choose its contents. Add element or Add page inserts a checked source draft with editor Undo. Use Find element to search names and descriptions, including imported components. Results respect the selected placement. Clearing search keeps the selected component and its entered fields; choosing another component starts with that component's defaults. Pressing Enter in search does not insert anything. If refreshed component contracts or available placements change, the panel clears obsolete fields and cancels pending insertion. Equivalent analysis refreshes preserve the fields you are editing. Local and imported components also appear, including definitions that have not yet been used. The choices follow the selected View's imports, aliases and local phrasebooks. Library-private helpers and another View's definitions stay out of that View's palette. Reusable elements list their required arguments in order; enter Grid expressions or bindings, and put text in double quotes. Native components expose their declared main value, writable binding or preset arguments. Remaining native properties, events and slots can be added through Properties after insertion.

The compiler checks the new use in its chosen scope, including argument counts, writable targets and native library locks. A missing library, unresolved name or invalid component body leaves the draft unchanged and shows the reason. Adding an element does not install its library. Edits stay in the calling View, preserving library definitions, existing comments and editor Undo. The form supports up to 256 fields totaling 64 KiB; larger argument lists remain in Code. Creating new model inputs also remains in Code. The panel appears only for an editable current draft. See the reusable element example.

Preview at Panel width, Phone, Tablet, Desktop, or a custom size from 240 to 2560 pixels. Fit to panel scales the display without changing the chosen viewport. CSS media queries use that viewport, and resizing preserves in-progress form drafts. This is a layout preview; trusted JavaScript and native libraries still share the workbench environment, so it is not a device emulator or an isolated script sandbox.

Inspect is the default: clicking an element reveals source without invoking its control. Choose Interact with live model to use controls that can change the connected model. Escape returns to inspection. Editing source also revokes live interaction until the draft is applied and live interaction is selected again. The Page controls navigate within the preview without changing the workbench URL. Page parameters require experimentation or live interaction because restoring them can write model inputs; each parameter must be a valid single route segment. Path placeholders map to page parameters in declaration order. Open page asks before leaving unsaved Form fields, then waits for the View's page inputs to be accepted. A refused input shows its message beside the picker; the current page and Form draft stay in place. While opening, the page controls and preview canvas wait for that attempt. Choosing Inspect, resetting, reloading, changing source or closing the preview cancels a pending page check. Returning to live interaction does not revive it. Cancellation does not undo a parameter write that the host already accepted.

Inspect pauses a live Form without discarding its fields. Returning to live interaction resumes that draft. Starting another copy, leaving a copy, or opening a CHECK setup asks before replacing unsaved Form fields; canceling keeps the same session. Resizing does not replace a draft. Reset copy and Reload preview remain explicit discard actions and need no second confirmation. Try a staged field in the validation example while switching modes; use the pages example to try parameter changes from the picker.

Choose Experiment in a copy to try an analyzed source draft against a private native model copy. You can change inputs, use local state and forms, navigate pages, and run model actions supported by that copy. Reset copy discards its changes and starts again from the current model inputs and source draft. Leaving experimentation or changing source discards the copy; switching to Live does not transfer experimental inputs, form drafts, or page parameters.

Choose Inspect copy to pause interactions while keeping the private copy and its Form drafts. Select a rendered element to open its draft source and Properties, even before the View's first Save. Turn off Inspect copy or choose Experiment in a copy to resume the same session. Preparation tools are hidden while inspecting. Writes already accepted by the host can still finish; queued new writes are refused. Editing source still retires the copy. Copy selections do not open live-model value inspection.

New Views can use this private preview before their first Save, including Views staged from an App conversion. Until the View is saved, Code explains that no saved preview exists and keeps Live disabled. Saving returns the preview to Inspect; choose Live explicitly to interact with the saved model. Opening a saved View in Code loads its compiled preview without first visiting another layer. If that request fails, the preview reports the error; use Reload preview to retry.

Open Set up inputs and local state to prepare values outside the preview viewport. Choose Model inputs or View local state, find an input, and stage its current value. Stage up to 256 values and apply them together. Values are literal numbers, text, Yes/No, Blank or structured JSON; formulas remain in source. Model inputs keep their validation and normal rules. Locals use the View's own constraints. Apply the two scopes separately. Restore default removes a model input override or restores a local's compiled initial value. If an input changes after staging, reload the staged values before trying again; that discards the staged edits. Each value is limited to 64 KiB and a batch to 3 MiB.

Save or load a preparation keeps a selected set of staged values for another experiment. Stage model inputs or View locals, give the preparation a name, then choose Save staged preparation. This downloads a JSON file without applying the values. Default-restoration choices and value types are retained. Save the two scopes separately. To capture a value you already changed in the preview, stage its current value first.

After resetting or reopening the copy, choose Open preparation file. The file must match this View and source identity. Loading opens its staged values for review and uses fresh copy revisions when applying them. Only listed values are affected; omitted values remain as they are. You can edit the preparation before applying it. Model inputs keep their normal validation and rules; locals keep their View constraints. Files contain up to 256 values, 64 KiB per value and 3 MiB overall. They contain selected values and source identity, not model source, page, rule clock, external resources, runtime or library snapshots.

Start from a CHECK setup reopens an existing CHECK's preparation in a fresh private preview. Choose a CHECK, then Open CHECK setup in a copy. Its initial given, reset and on steps run in order, stopping before the first interaction or expectation. References read the results of preceding setup steps. Model givens use the same validated native fixture path as a CHECK run, without firing normal input-change rules. reset Name clears a model input's override to restore its base/default, or restores a local's declared initial value. This differs from assigning BLANK. Local setup writes use the View's constraints, and on opens the declared page with its current parameter values. Later interactive edits run normal rules. Inputs omitted from the setup retain their copied current values.

Controls and page inputs stay unavailable until setup finishes. Reset copy starts over with the same CHECK setup; Experiment in a copy starts without it. A failed or interrupted setup requires a fresh copy. Setup supports 1 to 256 initial steps and never runs later interactions or expectations. Use Run checks for the complete CHECK and its result. Changing source or host support returns to Inspect.

Save setup in Code turns staged inputs or locals into a named source CHECK. Stage current values or load a preparation, edit the values and default choices, enter a CHECK name, then choose Save staged setup in Code. This adds a compiler-checked block to the current draft and selects its header. Code Undo reverses the insertion. The source change ends the current preview; open the new CHECK setup in a copy to try it again. Add interactions and expectations in Code before using Run checks to test behavior.

The Checks panel offers Run beside each CHECK and Rerun failed checks after a failure. Run checks runs all checks in source order; an individual run creates only its selected copy. Results appear as each copy finishes and is released, alongside the current check and progress. Retrying a check clears its old result while retaining the others. Results describe separate runs against copied model values, so they do not certify later input changes.

Cancel checks stops further steps and remaining checks, then releases the current copy. If copy creation is in progress, cancellation waits for its identifier so that the copy can be released. Completed results remain visible; unfinished checks receive no pass or failure. A cleanup failure appears with recovery guidance. Changing source, model, partition, dependencies or host support clears the displayed results and ignores late replies. Select a result to open its failing step or CHECK declaration in Code.

Try the report button example: run either CHECK alone, then run both. Each resets the count in its own copy. To try failure recovery, change the first expectation from 2 to 3, run both, and use Rerun failed checks. Correct the expectation in Code and run again; source edits clear the previous results.

Capture retains literal types, structured JSON and exact numeric strings, using literal JSON and TYPE_TAG annotations where needed. Default choices become reset steps. Local records are not interpreted as model input envelopes. Save one scope at a time, with up to 256 values and 64 KiB of combined capture fields. For larger sets, select fewer values or download a preparation file. Omitted inputs, page, clock and external state are not captured. A name shadowed by a local or a duplicate CHECK name is refused rather than silently changing meaning. Capture requires editable source and host authoring support; source, model, partition or copy changes cancel pending edits.

For the report-counter example, open each click runs the report as a setup. The counter starts at zero; the two presses and expectation have not run. Click Run report in the preview to try the interaction, then reset the copy to start at zero again.

Use a saved input scenario reuses scenarios saved under Saved scenarios in I/O. Choose Refresh scenarios, select one from this model's Files, and choose Stage scenario inputs. You can also open a scenario JSON file. Its source text and source identity must match the private copy. The preparation opens for review: saved overrides retain their value types, and inputs absent from the scenario are marked Restore default. Apply or discard existing staged edits before loading another scenario.

Applying uses the private copy's current revisions and ordinary validated input writes. Model rules run normally; the connected model is unchanged. Scenario files are limited to 2 MiB, and preparation supports up to 256 public inputs with 64 KiB per saved value. Native resource references and unknown or ambiguous inputs are refused. This imports model inputs only: local state, page, clock, external data, runtime and package versions are not restored or verified. Use Start from a CHECK setup for source-authored fixtures. For the canonical Order View, save an I/O scenario for qty, change its value, then stage the saved scenario in a copy and review the recalculated total.

Advance rule time steps the private native rule clock by 1 to 60,000 milliseconds. It runs due scheduled rules, debounce and held outcomes through the same evaluator and refreshes the preview. Rule time stays paused between operations; a step is one scheduler operation, not a replay of every elapsed tick. JavaScript timers, animations and date functions continue to use real time. An uncertain time-step reply requires Reset copy before continuing. Older hosts without a reported rule clock keep input experimentation available.

For a starting exercise, open the canonical Order View, choose Experiment in a copy, stage a different qty, and apply it. Check the updated total, then restore the input's default. Reset the copy to discard all experimental changes.

The copy uses the same native evaluator and the private CHECK session boundary. It has no live jobs, connectors, external page fetches, source writes, or navigation to another View. Clipboard and download actions are refused. It does not run a background scheduler: delayed native outcomes advance only with explicit rule-time steps. Values tagged button, including computed and named cells, can trigger their normal WHEN rules in the copy and in CHECK runs. Each acknowledged click has a distinct touch value even while rule time is paused. These are button operations; other computed values remain read-only. An uncertain touch acknowledgement requires Reset copy. The computed-button example shows a report counter with a two-click CHECK. In the live workbench, named button cells use the same input-override path as cell-address button targets. Trusted scripts and imported components retain their usual browser permissions; model-copy isolation is not JavaScript sandboxing. A host that lacks private session support reports that limit before experimentation when it advertises its tools. Older hosts can report an error with Reset and Inspect as recovery choices; the experiment never switches to live writes. Copies expire after 15 idle minutes.

Availability and recovery shows the connected host's authoring tools, dependency resolutions observed during analysis, the View's required capabilities, and the workspace's actual custom-UI trust policy. A resolved import does not prove that its runtime assets, credentials or model actions are ready. Unsupported advertised tools are disabled; an older host without this report retains its existing compiler-provided source controls and is identified as unreported. Trust restrictions disable live interaction, private experimentation and checks that would require authored code. They do not prevent editing the source or inspecting installed library locks.

Choose Check library locks to inspect the exact libraries recorded in this View's compiler manifest. This checks installed lock metadata and retained contract source without loading executable runtime assets. Preview loading separately verifies those assets. A missing runtime pin, changed contract or missing source remains an error; a newer installed version is not substituted. Results belong to the current model, partition and draft, and are discarded when those change.

Review model dependencies opens the existing dependency tools; Review Connections opens the service connection workspace. After repairing an import or reconnecting a host, Refresh availability repeats the current draft's analysis across open Code panes. Package environment changes also refresh that analysis. Reload preview retries the renderer and its library loading, discards preview form drafts and navigation, and returns to Inspect; it does not save source or reverse acknowledged model writes. To see the pure-data case, open the order example and inspect its manifest before adding imported components. Publishing a sandboxed app and changing deployment trust remain separate, explicit operations.

Failed checks and private-copy preparation now show recovery controls beside the host message. Open related source opens the failed CHECK step or its setup; a failure before an individual check opens the View declaration. Open Dependencies, Open Connections and Refresh host availability use the existing workspaces and source analysis. Structured authentication and permission refusals explain when to reconnect or review access with the deployment owner; error wording alone is not interpreted as an authorization decision.

For a private-copy failure, Start a fresh copy repeats admission and any selected CHECK setup; Return to Inspect leaves experimentation. These controls remain above the preview and usable even when a failed setup disables its controls. They never enable live interaction or replay an uncertain model action. The report counter example includes a CHECK setup that restores its input before clicking the computed button.

Check outcomes describe the last run. Starting another run removes the old result; a failed attempt cannot leave an earlier pass showing. Changing model, partition, source, host capability or the observed package environment clears results and cancels pending runs. A changed model, partition or environment also returns the preview to Inspect. Later input edits do not continuously rerun or revalidate checks. Deployment-specific credential discovery remains with the connected host's administration tools.

Preview failures collects errors observed while this preview runs: script or locked-library startup, SCRIPT callbacks, imported property preparation and rendering, embedded surface rendering, and providers around the View. Select Open related source to reach a compiler-reported declaring line; a failure without an exact location opens the View declaration. Imported internals remain in their library source. Bounded argument descriptions can help reproduce a callback failure. Views with sensitive locals redact both messages and arguments.

Each Code editor, model, partition, source and environment has its own report. Private drafts can contribute diagnostics from their own copy; the last accepted preview cannot place runtime markers on a newer draft. Reset, reload, leaving a copy or changing context discards that attempt's report, and late failures cannot enter the replacement attempt. At most 64 distinct failures are retained per attempt. These are observed failures, not a promise that every JavaScript task succeeded: exceptions outside the renderer and its wrapped callbacks still use the browser's debugging tools. Native component inputs or source changes can retry a failed render; merely displaying its error does not retry it.

These edits preserve surrounding source, comments, and embedded payloads. The compiler checks the candidate using the model's imports before returning an edit; stale source, unsupported fields, and invalid candidates are refused. Scope-changing structural edits, validation for indirect/local/cell-address bindings and library definitions remain authored in Code. Imported expansions stay at their caller's use line, and embedded modules are opaque outline leaves. Generated surface slots remain read-only.

See Code authoring for editing and inspecting source-declared interfaces.

Renderer style layers

Source Views apply first-party element defaults in grid-view-base, imported library styles in grid-view-library, kit styles in grid-view-kit, and author STYLE in grid-view-author. The frontend CSS transform is restricted to the three existing first-party App/input sheets. It preserves their ordinary App selectors outside .grid-view and places copies inside the View base layer; third-party and project styles are not transformed.

This has a measured frontend download cost. On the implementation source, those three sheets increased from 610,056 to 660,212 minified bytes (+50,156), and from 91,864 to 95,329 gzip bytes (+3,465), using esbuild CSS minification and Node gzip on their combined contents. The unminified increase was 54,979 bytes. These are source-sheet measurements, not a full product bundle or a browser-latency result. Ordinary App style matching also gains an exclusion selector; that rendering cost is not represented by the byte measurements. The transform runs at frontend compilation, creates no browser worker, observer, or polling loop, and adds no work to model evaluation or resolve.

Live View nodes retain their existing renderer hooks and add stable app-* semantic classes. Framework archives can select Plain, DaisyUI, or Tailwind. For an external kit, the integrating project passes its compiled stylesheet text as kitCss and includes the exported view-kit.js in class scanning. The adapter applies this stylesheet inside its shadow root, in the kit layer; root variables and nested rules remain scoped to the mounted View. The author layer follows the kit. Stylesheets are supplied by the host project, never fetched or installed implicitly.

The shared App renderer adds one optional callback check at each converted class site. An ordinary App returns the original class string and does not allocate a class map or cache. A selected View allocates one mapping cache per kit identity and expands each distinct class string once. The shared renderer module alone grows from 54,690 to 56,820 minified JavaScript bytes (+2,130), and from 15,488 to 15,866 gzip bytes (+378), using esbuild ES2022/automatic-JSX module transformation. This is not a full bundle measurement. Callback latency has not yet been measured in a browser. This UI adaptation creates no model-evaluation or resolve work.

In Code, the source outline follows the compiler's declaration tree. Expand pages and containers with the arrow keys, then select an item to reveal its exact source. For an accepted View, Inspect reveals the clicked element without executing its action. Source selection and live interaction are unavailable while the preview belongs to older source. The outline remains a source projection; its property controls apply compiler-checked edits to the same source editor.

Follow a displayed value to its calculation

In Inspect, select a rendered element and choose a value under Model values for this element. Code opens its live value inspector. Why this value? requests a bounded runtime trace; each dependency offers source navigation and further value inspection. Selection alone does not load values or request a trace.

For compiler-generated values, Code shows the View name, authored expression and source line. Go to definition returns to that line, including from a projected View declaration. A reused expression may lead to its first recorded source site. Code withholds locations when the source is stale, the compiler has no exact location, or the metadata is ambiguous. Save or revert the draft and refresh source analysis before trying again.

These values belong to the accepted model. Unsaved Form fields, browser-local values and repeated row fields remain in their preview. Entering live interaction or a private copy clears the selected-element list; private-copy values are not presented as live-model provenance. Choosing a container with no direct reads does not select all of its children.

Try the Order example: select the total in Inspect, open its value and choose Why this value? to follow qty and price. To try an inline calculation, add Metric qty * price AS "Calculated total" inside the View, save, and inspect it. Its generated value should show the authored expression and line; use Go to definition to return to that line. Full native-host acceptance and native/CLI diagnostic lineage remain under development.

Recover a failed model value

A failed model read in a mounted Code preview now appears under Preview failures and in Code's Problems list. Open related source uses the compiler's expression span when one is available; otherwise it opens the declaring element or View. Known generated names in error details are shown as authored expressions and source lines. Unknown generated names do not acquire a guessed location. Native error objects display their message or error code, rather than an object placeholder.

For accepted live-model previews, Inspect failed value opens the same value inspector and explicit Why this value? trace. The report never retries a write or requests provenance automatically. Private copies retain their own source links and reset controls, with no shortcut into live-model value inspection. Reports describe observations in the current preview attempt; reloading or starting a fresh copy clears them. A report may remain after an input recovers.

To try this with the Order example, add Metric qty / (qty - 2) AS "Review calculation" inside the View and save. The default quantity exercises division by zero. Open the reported expression, inspect the failed value, then repair the expression and save again. The preview only observes values it already has; it does not load every model calculation to search for errors. Ordinary text and record values are not rewritten as messages.

Framework exports and static capture

Views export through the same renderer into React, Vue, Svelte, and Solid. The Vue/Svelte/Solid artifacts contain a lifecycle adapter and a closed copy of the Grid renderer; the integrating app supplies its existing Grid transport and viewer services. Input edits require acknowledged atomic commits. A host that cannot acknowledge a write cannot silently report it as saved. Native React library and embedded native surface nodes retain explicit target diagnostics on non-React exports.

React’s ui.GridView and exported Vue, Svelte and Solid components accept onReady and onUpdate callbacks. onReady gives your app the mounted View handle, and receives null when it is removed. Before changing your router URL, await handle.navigate(path) and move the URL only when it returns true. The View asks about unsaved Forms and waits for page inputs to be accepted. Cancellation or validation failure keeps the current page and draft. Failures appear beside the View.

You can also pass a path prop. onUpdate reports { accepted, path, message? }; on refusal, path is the retained route so your app can restore its URL. Changing the source or model connection also asks before replacing a dirty Form. Updating kit styles, or echoing the already accepted route, keeps the same draft. A newer update or unmount cancels pending page checks; a late reply cannot write through the retired attempt. Writes already accepted by the host are not undone.

Before removing the component, call handle.canLeave() and keep it mounted if the answer is false. handle.hasUnsavedChanges() supplies close/update status. Hosts with an existing navigation owner may pass app.registerNavigationGuard instead and consult that registration before removal. Framework cleanup and handle.destroy() always release resources; they cannot veto a route that has already removed the component. The Vue/Svelte/Solid README includes this contract. React receives its host registration through the Component’s binding connection; a direct GridViewComponent integration supplies it through bindings. React unmount owns cleanup, so its handle exposes navigation and status without a destroy method. Changes to compiled source, SCRIPT source, model connection or partition retain the current React View until its dirty Form can be left. Native React elements keep their existing renderer and library support. A refused replacement cannot expand the retained View’s write permissions; reductions still apply immediately. Equivalent document props and host callback updates keep the current Form. A home page with parameters requires an explicit concrete initial path.

Try exporting or ejecting the model field validation example: change Reference without saving, then request removal through the handle's guard. Cancel and confirm that Reference is still editable with its draft intact. With a paged View, try a refused page parameter and then an accepted one before updating your router URL. In a React Component, pass onReady to ui.GridView, keep its handle in a ref, and check handle.canLeave() before changing the state that removes it. Cancel once to retain the draft, then allow removal and confirm that onReady receives null.

Static HTML capture records the currently rendered page and local draft values. It does not execute new model operations, and its controls are inert. It is not a full paged-table export: rows outside the current rendered page are not added. The snapshot says that it contains only displayed rows. Printing includes all already loaded array rows; a resident table prints its current page with a partial-data notice.

Running CHECK outside the Code layer

The maintained CLI operation runs the same accessible-control driver and view renderer as the Code layer. It requires an already running model host, an already built matching view runtime, and explicitly installed Playwright with Chromium. It never starts a Build or installs browser dependencies. The reusable local helper belongs to the Testing domain:

node tools/testing/run-view-checks.mjs --runtime dist/frontend/grid-view-runtime --project . --source model.grid --surface Desk --model MODEL_ID --api-host http://127.0.0.1:3000

--token-env NAME can select an existing API bearer-token environment variable. The token stays in the Node process. A temporary loopback server admits only source analysis, private CHECK sessions it created, and reads of pinned library assets for the selected model. The browser cannot use it for live-model writes or arbitrary host requests. Every check still executes in the host's private native calculation session. Completion and cancellation retire those sessions; an unreachable host retains its existing expiry fallback. A deployment that selects lifecycle-v3 durable receipts refuses CHECK session and library requests before reading their bodies, because starting a session loads the live model; run checks against an ordinary deployment.

The helper verifies selected runtime bytes before starting Chromium. Its JSON report carries check names, outcomes, and source locations. Embedded JavaScript is typechecked before interaction checks, using the Code layer's compiler-owned virtual documents and the project's explicitly installed TypeScript 5.x. Unknown names, malformed JavaScript, and incompatible expression result types map back to their original Grid source. Typechecking never evaluates author scripts or loads their imports. A failed typecheck or CHECK returns an unsuccessful exit status; a source without checks or JavaScript reports that no checks ran. This is an explicit Testing operation, never a condition for Build, Release, Deploy, or Verify.

The independent CLI's gridctl surface check Desk --model MODEL_ID --source model.grid --runtime dist/frontend/grid-view-runtime --project . also discovers immediate sibling *.test.js, *.test.mjs, *.test.cjs and matching *.spec.* files. It runs ordinary node:test tests with installed Node 22 or later, under one bounded deadline with the browser checks. Author tests use ordinary local Node authority. The CLI clears its API credential variables before running them, pins the model source for both phases, and reports source or test-file drift. Missing, skipped, passed and failed JavaScript tests remain distinct in the combined report.

The runtime manifest records a dependency closure for each entry. Published views copy the publication closure; framework exports add their mount adapter; CHECK selects its own closure. Optional check-driver JavaScript is not included in ordinary published View artifacts.

View theme CSS properties

The View root exposes --accent and --surface-accent for the theme accent, --radius for the selected corner radius, and --gap for density spacing. Mode supplies --bg-surface, --app-fg, --app-muted, --border-default, and --border-subtle. Imported components inherit these properties. Use them in STYLE with var(--accent), for example; Code offers the same property names. mode :system follows the viewer's light/dark preference. contentWidth :reading limits the view to 72rem; :full uses the available width.

Responsive hide phrases use the view's available container width: mobile up to 640px, tablet from 641px to 1024px, and desktop above 1024px. Universal classes survive document loading and reach imported components as className. Default-mode Views retain an outer layout/paint boundary that author root styles cannot remove. Print mode lifts that boundary for pagination.

Declared VALIDATE IN lists and CHOICE members supply selection options. Model-dependent numeric bounds remain reactive. Literal validation on locals also supplies options and bounds; small bounded integer ranges infer a slider, including inside a Form. A placement before the first PAGE is shared by all pages; a top-level placement after a PAGE belongs to that page.

When a Form has unsaved fields, changing the host's page, View, workbook tab, layer, model or folder asks before leaving. Cancel keeps the current route and draft. Browser Back and Forward use the same protection; for routes created by Grid, canceling restores the history position so you can retry the same move. The desktop close prompt and update protection also include these drafts. A private Code copy registers its Form draft with the workbench without receiving live model write access. An approved prompt alone does not save or clear fields; they remain until the navigation succeeds or the View closes.

Published Views use the same outer-app protection, including Home, Edit model, browser Back/Forward and desktop close. Their own page buttons ask through the host, so canceling keeps the Form inside its sandbox. The View sends only whether it has unsaved fields; it does not send the draft's values for this protection. Newly published Views require an updated Grid host and show an update message when that host support is missing. If a page's input validation refuses a move, the old Form remains protected.

Try the model field validation example: change Reference without saving, then choose Code or open the model browser. Cancel and continue editing the same draft. Save the Form before leaving to avoid the prompt. After publishing this example on an updated Grid host, repeat the same canceled move from its app page. Explicit Reload preview and Reset copy retain their documented discard behavior. Hosts embedding a View outside the workbench must supply their own navigation protection; the View still protects its own page actions and browser unload.

Model VALIDATE LIKE, ILIKE, STARTS WITH, ENDS WITH and CONTAINS clauses supply control feedback, as does equality on text and Boolean inputs. The author's MESSAGE appears beside an invalid draft. The draft is retained, and a Form's Save action stays unavailable until its fields satisfy these rules. Changing a referenced input refreshes both the field message and the Save action; this does not modify the committed value.

A direct model operand, including a plain alias, reads that input's staged value inside the same Form. On hosts with native validation, Check values checks the complete proposed batch without writing it and displays returned field messages. Save checks again before committing. Computed operands are evaluated by the native host; the browser does not evaluate their expressions against unsaved inputs. Native input validation remains authoritative when saving: the host checks the complete proposed input batch, so a computed operand sees every submitted change and any restored defaults. It rejects a failing batch before writing any member. This requires the updated native host. The detached native check uses resident data; a missing/error operand or a dependency requiring new external work refuses the batch without launching that work. Models whose native capabilities cannot be cloned also refuse the check. Wider capability coverage remains unfinished. Native field messages also cover numeric and structured comparisons, including exact numbers and typed records; there is no separate browser implementation of those comparisons. Hosts without native validation retain limited local feedback and cannot offer Check values.

Open examples/canonical/grid-view-model-text-validation.grid. Change the reference to NEW-101, then change its prefix to NEW-: the Form clears the message and saves both inputs together. Select Reference in Code's outline and edit Input validation to change the owning rule and its message. The checked source change shares Code Undo and applies everywhere the input is used. These are input contracts; separate record/table field declarations remain unfinished.

Use Link "Documentation" to "https://example.com/docs" for a captioned external link; the destination can also be a model binding. SCRIPT exports must not shadow a binding or element. Import a library element with an explicit alias when its exported name matches a standard element.

Universal token scales are checked on literals at compile time and on bound/glue values when they arrive. tone accepts :neutral, :info, :success, :warning, or :danger; align accepts :start, :center, :end, :stretch, :left, :right, or :justify. gap is a number from 0 through 64 pixels; span is a positive integer. Width tokens remain :narrow, :half, :wide, and :full; imported element contracts with a numeric width keep that numeric setting. Invalid dynamic tokens show a property error instead of being coerced into an unrelated style.

Computed drawings in Views

Grid 0.67.0 includes an initial drawing workspace. Large-drawing latency targets and broader host, image/export and resource-retention coverage remain follow-up work for 0.67.1. See the release notes.

A Drawing is a coordinate viewport in an ordinary View. Geometry and appearance use the same native Grid expressions as the rest of the model. A Graphic embeds an existing DRAW_* result, numeric pixel array, native image, or inert SVG image. Use Label for vector text and Overlay for ordinary controls and View layout.

input center = [180, 140]
input radius = 40
input caption = "Station"
 
SURFACE Diagram AS "Diagram"
  Drawing size [640, 360] label "Station diagram"
    Circle at center radius radius
      fill MAKE_COLOR(47, 111, 237)
      stroke "#173875"
      stroke width 2
    Label caption at [24, 28] font size 18
    Handle center label "Station position"
    Overlay at [400, 24] size [216, 180]
      Stack gap 12
        TextInput caption label "Caption"
        NumberInput radius label "Radius"
END

See the complete example.

Positions, sizes, and radii pairs are ordinary two-number arrays. X increases to the right, Y downwards. Group translate [x, y] rotate degrees scale [sx, sy] applies scale, clockwise rotation, then translation. A Label position is its text baseline. A Drawing defaults to [512, 512]; Code insertion writes size [640, 360] explicitly. fit :contain centers and preserves aspect ratio; fit :actual uses one CSS pixel per logical unit. The viewport clips all layers. Graphics follow source order, overlays sit above graphics, and handles sit above both. HTML controls do not interleave with individual strokes.

The standard drawing elements are Drawing, Group, Graphic, Line, Polyline, Rect, Circle, Ellipse, Arc, Path, Label, Overlay, and Handle. Their Properties and insertion forms come from the standard component catalog. Specific geometry phrases take precedence over presentation phrases: Drawing size [640, 360] accepts a pair, while text size tokens retain their existing meaning. Use ordinary FOR with stable keys, conditions, reusable ELEMENT definitions, and native calculations. Shapes and groups support on click -> ...; keyboard activation invokes that same action.

A Handle edits one explicitly writable coordinate pair atomically. A stored record field such as Handle Station.position is also supported when the compiler proves its writable owner and pair shape. The guarded transaction preserves sibling fields and checks the revision of the owning input. Dynamic indexing and computed inverses are not writable handle targets. commit :live is the default; commit :release sends the final position when released. axis :x or axis :y restricts motion. A positive step snaps positions; without it, pointer movement is continuous and arrow keys move one logical unit. Enter opens numeric coordinates. Updates use guarded native writes with revision receipts, one write in flight and one latest pending value. Handles keep their on-screen size when the drawing is zoomed or fitted. Conflicts stop the gesture and retain its draft. Escape cancels unsent movement and pending input validation; it does not reverse a committed write. Revert gesture restores the initial position only if its revision guard still matches. Within a Form, the handle stages and previews until Save. A successful Save or Discard clears the previous gesture feedback. Hosts without the required guarded-write capability show the handle as unavailable.

In Code, Draw adds selection, movement, resizing, group rotation, pan, zoom, and fit to the View preview. Shift-click selects multiple authored objects. The insertion panel and Properties retain ordinary source expressions. A literal can be moved visually; an input requires an explicit Handle or control; a derived expression stays intact. Add transform wraps computed geometry in a Group. Repeated instances edit their common template. Selecting an imported drawing identifies its caller placement and library owner. Its arguments remain editable in the caller; Add transform wraps that placement without changing the library or replacing its formulas. Completed source gestures use checked compiler edits and one Code Undo step. Live model gestures are separate from source Undo. Ungroup distributes literal transforms into individual placement Groups, preserving computed child geometry. A shared computed transform or behavior keeps its Group and receives an explanation instead of an inferred rewrite.

Artwork SVG exports the resolved graphics layer; interactive overlays are excluded. View print/snapshot opens Print Studio with the saved View selected and includes the complete composition and ordinary controls. It does not export private experimental input values; save or inspect those separately. Neither writes model inputs. Native raster exports through DRAW_RENDER and DRAW_RENDER_RGB explicitly reject text until native text rasterization exists. Paths support absolute M, L, C, and Z, not general SVG path syntax.

Graphic grayscale values use range :unit by default. Choose :byte for 0–255 values or :auto for legacy automatic normalization. Existing Canvas configurations keep automatic normalization when no range is specified. SVG text is displayed as an inert image document and is never inserted as application HTML.

A Drawing admits at most 10,000 expanded graphic primitives and handles, 256 Overlay roots, and 64 nested Groups. Invalid or oversized updates retain the last valid artwork and show a source-linked error. The native scene and raster limits still apply. These limits are admission rules, not performance claims.