Interactions
A document can say what a screen looks like. This page is about the other half: what happens when someone clicks something.
screen InvoiceList on enter refresh Invoices
table Invoices column invoiceId on double click open dialog InvoiceDetails with invoiceId from item.invoiceIdThree words carry the whole idea:
| Word | What it is |
|---|---|
| Interaction trigger | What starts it — the on <thing> clause. |
| Action | What happens — execute, navigate to, open dialog, refresh, and the rest of a closed set. |
| Behavior | A bundle of trigger-to-action bindings, attached to something. |
For one labeled button that selects a command from the current item’s state, use a guarded screen action. For a gesture that chooses a whole action list, use block-form alternatives below.
Write it inline, or name it
Section titled “Write it inline, or name it”Most interaction is one trigger and one action, written where it belongs:
button on click execute RegisterInvoiceThat inline on block is a behavior — an anonymous one, attached to the button. When the same wiring is wanted in several places, give it a name, declare parameters, and attach it with uses:
behavior ConfirmThenExecute parameter command parameter message
on click confirm message on success execute command
module Invoicing feature InvoiceManagement slice StateChange CancelInvoice screen CancelInvoice uses ConfirmThenExecute command CancelInvoice message $strings.confirmCancelThere is one construct behind both forms, so a named behavior and an inline block resolve, print and diagnose identically. The only difference is the name.
Interaction triggers
Section titled “Interaction triggers”An interaction trigger is never declared. It exists only as the on clause of a binding.
| Trigger | Occurs when | Carries |
|---|---|---|
on click | the element is activated — clicked, tapped, or confirmed from the keyboard | the element’s data item, if any |
on double click | it is activated twice | the element’s data item |
on select | selection changes in an items control | the selected item |
on submit | a form is submitted and passes the modeled validation | the form’s values |
on change | a bound value changes | the old and new value |
on load / on unload | the element or screen becomes live, or is torn down | route parameters |
on enter / on leave | the screen is navigated to, or away from | route parameters |
on event <Event> | a modeled domain event is observed | the event’s payload |
on interval <n> <unit> | a timer elapses | — |
on <ApplicationTrigger> | a declared application trigger fires | that trigger’s declared payload |
The last two rows are the bridge to the backend vocabulary, and the reason this page distinguishes two kinds of trigger.
triggerstill means one thing. A declaredtrigger <Name>is an application trigger - a signal with a payload shape that areaction ... whenconsumes. See Triggers. What starts an interaction is the anonymousonclause above. The built-in kinds (click,submit,enter, and their siblings) are reserved inside anonclause only; an identifier of the same name anywhere else in a document is just an identifier. Declaring an application trigger named after one of them is an error, becauseon <Name>would then mean the interaction and never the trigger.
Choose an action list by item state
Section titled “Choose an action list by item state”on click, on double click and on select can choose one whole action list:
table Invoices column status on double click when item.status == "draft" open dialog InvoiceDetails with invoiceId from item.invoiceId otherwise notify info "Only draft invoices can be edited"Use exactly the guarded action condition grammar: item.<path> compared with a literal, combined with and, or and parentheses. Each when and the optional final otherwise contains a non-empty indented list. At least one when is required. Plain actions and where cannot mix with alternatives. The one-line when … execute … spelling belongs to labeled actions, not interactions.
The first matching branch runs once against the rendered item when the gesture occurs: no refetch first, no re-evaluation while the list runs. No match runs the fallback if present, otherwise nothing. No subject runs nothing, including fallback. Failure, denial or unavailable commands never fall through; commands still enforce their own rules. This differs from a labeled action’s click-time refresh check because the interaction displays no choice beforehand.
A table’s click or double click uses the activated row; select uses the newly selected item. Clearing selection runs nothing. Other elements use the nearest enclosing container’s single item or selected row, with the same sibling precedence as guarded actions. Named behaviors are checked at each uses site. A component’s context binding or selectedItem does not supply a subject in this version; unresolved or equally near data subjects produce PLAY0346.
on submit has no alternatives: item means populated data, not submitted form values. Event, change, interval and application triggers also have no alternatives. The one-line on row-click navigate to … by … stays unchanged.
Opaque where is deprecated only on click, double click and select (PLAY0564). A strict item condition produces a warning and a C# typed repair to one when block with no fallback; repairs require individual review and refuse comment loss. Other guard text produces Information without a repair. Event/change/application where remains opaque and unchanged. TypeScript reports the same diagnostics but does not offer these repairs.
Actions
Section titled “Actions”Every action names something the document declares. That is what makes an action that points at nothing a diagnostic rather than a control that quietly does nothing.
| Action | Effect | Resolves against |
|---|---|---|
execute <Command> | submits a modeled command | the document’s commands |
navigate to <Screen> | changes the active screen | the document’s screens |
navigate back | pops navigation history | — |
open dialog <DialogTemplate> | opens a dialog over the application | the module’s dialog templates |
close dialog | dismisses the innermost dialog | — |
refresh <Query> | re-runs a query-backed element | the document’s queries |
set <target> to <value> | writes screen state | the screen’s declared state |
notify <info|warning|error> "<text>" | surfaces a message | $strings. accepted |
confirm "<text>" | gates the actions that follow on the user agreeing | — |
raise <ApplicationTrigger> | fires a declared application trigger | the document’s triggers |
Arguments are passed with with <name> from <binding>:
on click open dialog InvoiceDetails with invoiceId from item.invoiceIdA message operand may be a literal, a $strings. key, or the name of a parameter the attachment supplies — which is how one named behavior serves several call sites.
Continuations
Section titled “Continuations”An action that has an outcome can branch on it:
on click execute RegisterInvoice on success close dialog refresh InvoiceList notify info $strings.invoiceRegistered on failure notify error $strings.registerFailedActions run in the order they are written. confirm short-circuits everything after it when the user declines.
| Continuation | Valid on |
|---|---|
on success, on failure | execute, refresh, confirm, open dialog, raise — the actions that can fail |
on result | open dialog only |
Attaching on success to a navigate, a notify, a set or a close dialog is an error. Those have no outcome to branch on, so the continuation could never run — and an author who wrote one expected it to.
Writing actions after an unconditional navigate is reported too: the screen they were written for is already gone.
Returned values in continuations
Section titled “Returned values in continuations”After a command succeeds, you can pass its response to the next action by name. A scalar returns invoiceId exposes invoiceId; a returns block exposes its field names. Those names are available in the form’s one-line or block on submit, and in on success beneath execute <Command>.
A bare value in with … from …, set … to …, or an unquoted notify / confirm message resolves to the nearest successful command response that supplies that name. A form field or behavior parameter with the same name keeps its existing meaning. Dotted paths, $-rooted bindings, quoted literals and other opaque text are unchanged. Action declaration names and state-write targets are not response operands.
A nested command’s on success shadows matching outer response names only inside that subtree; siblings restore the outer scope. Its on failure cannot use its returned names (PLAY0685), but can still use an outer command’s successful response. Continuations of refresh, confirm, open dialog and raise inherit their surrounding value scope rather than creating a response. A parameterized execute command inside a named behavior has no known response shape at declaration time.
Monaco and VS Code complete returned names after from and the form sugar’s by, and hover shows the field type. This is an authoring contract outside the ESM: renderers must bind response values. Screen action <Command> navigation sugar does not gain a response scope.
Where a behavior attaches
Section titled “Where a behavior attaches”A behavior attaches at every level of the containment tree, and means the same thing at each:
| Level | Reaches |
|---|---|
layout | every screen in the application |
module | every screen in the module |
feature | every screen in the feature, including nested ones |
screen template, dialog template | every screen that uses it |
form | that form |
screen, section, slot, table | that element and what is inside it |
module Invoicing uses ConfirmDestructive
screen template Workspace fits slot main content
on enter refresh InvoicesIn a form body, on submit navigate to <Screen> keeps its existing one-line meaning. Any other on is a behavior attached to the form.
Attachments are additive. A behavior on a template and a behavior on an element both run — the more specific one does not replace the less specific one. They run outermost first, unless a behavior declares its own order:
behavior ConfirmDestructive order 10 ...This is the same outward-resolving rule contributions already use.
In a folder of files, a module’s or a feature’s attachments may be written in any file that names it, and they accumulate the same way. An attachment identical to one another file already makes is ignored with a warning rather than run twice; expansion writes them back into the owner’s own file.
What the compiler checks
Section titled “What the compiler checks”- Every operand resolves, or is reported. Unknown commands, screens, queries, dialog templates, events, triggers and behaviors are warnings, the way every other reference in the document is — a name may still resolve to something outside it, and what matters is that the gap stays visible.
- A
usessite must supply exactly the parameters the behavior declares. A missing or unknown argument is an error. - Continuations must sit on actions that can fail, and
on resultonly onopen dialog. - Nesting is capped. Continuations nest arbitrarily in principle; past sixteen levels the compiler asks for a named behavior instead of reporting a stack overflow.
The full list, with codes, is in Diagnostics.
What this is not
Section titled “What this is not”Interaction is a closed vocabulary, deliberately. It is not a scripting language: conditions use the existing expression grammar, and actions are a fixed, resolvable set. Validation stays modeled on the command — the UI surfaces it rather than restating it. Animation, visual states, drag-and-drop and keyboard maps are not part of it.
The event model board draws the containing table or screen as a static prototype; it does not execute gesture action lists or invent a button for each branch. Runtime support belongs to renderers, which must reject alternatives they cannot realize.
Interaction constructs are deferred from the backend ESM v1 profile, the same way screen, layout and ui profile are, and report PLAY0269. Deferred does not mean dropped: the syntax tree, the printer and the semantic model carry every construct in full, and a target that cannot realize one reports it.
See also
Section titled “See also”- Triggers — application triggers, and how an interaction reaches them.
- Screens — what a behavior attaches to.
- Layouts and templates — the shapes a screen fills.
- Glossary — one line per term.