QORMQORM v0.8.4 docs Get started

Example: Login

A styled login form — text inputs, bound state, and a submit button. Source: examples/login.

qorm run examples/login

The pieces

Global state holds the form fields and status (in qorm.json):

"globalState": {
  "schema": { "email": "string", "password": "string", "isLoggingIn": "boolean", "errorMessage": "string" },
  "initial": { "email": "", "password": "", "isLoggingIn": false, "errorMessage": "" }
}

Inputs bind two-way to the fields, and the submit button invokes an action with the entered values:

{ "type": "input", "id": "email", "binding": "email", "placeholder": "Email Address" }
{ "type": "button", "id": "submit", "label": "Sign In",
  "onPress": { "type": "invoke", "name": "performLogin", "args": { "email": "{{state.email}}", "password": "{{state.password}}" } } }

Fields also carry the browser's native input attributes — they cost nothing and give the user immediate feedback and the right on-screen keyboard:

{ "type": "input", "id": "email", "binding": "email", "placeholder": "Email Address",
  "inputMode": "email", "required": true, "autocomplete": "email", "autofocus": true }
{ "type": "input", "id": "password", "binding": "password", "placeholder": "Password",
  "required": true, "maxLength": 64, "pattern": ".{8,}", "autocomplete": "current-password" }

These are native constraints, not a validation engine — they cannot express "passwords must match". But they can stop a submission: put the fields in a form and mark the submit button "submit": true, and the browser's own check gates the dispatch, showing its message bubble on the offending field instead of running the action. A "submit": false button (Cancel) is never gated, and "novalidate": true on the form turns the whole check off. See First action.

Without a form, or on a button that carries neither prop, nothing is gated: the button's onPress dispatches from its own click handler. Bind the button's disabled to a validity expression for that case, and keep the message in state.

An error line binds to state so a failed attempt shows a message:

{ "type": "text", "id": "err", "text": "{{state.errorMessage}}" }

This flow can be exercised against the running app with qorm check (layout audit) or the agent-side qorm_assert / qorm_dispatch MCP tools — see verification.

Format notes

and passes state values as args.

required, maxLength, pattern (input only), inputMode, autofocus, readonly, autocomplete.