QORMQORM v0.9.8 docs Get started

Responsive layout

QORM renders responsive UIs server-side: the browser reports its viewport over /viewport, the runtime re-evaluates bindings, and SSE pushes the updated HTML. Use the when node to swap between alternative subtrees (unlike if / visible, which hide a single node in place).

Runnable reference: examples/responsive.

Viewport variables

Every scene binding can read:

VariableTypeMeaning
viewport.widthnumberwindow width in px (0 while unknown)
viewport.heightnumberwindow height in px
viewport.orientationstring"portrait" / "landscape" / "" while unknown

The server's first frame runs before the client reports its size, so viewport.width is 0 and orientation is empty — when conditions evaluate falsy and the else branch renders until the client posts its viewport.

Breakpoint variables

Declare named width thresholds in qorm.json:

{
  "breakpoints": { "sm": 640, "md": 768, "lg": 1024, "xl": 1280 }
}

Omit breakpoints to use the same defaults (sm 640, md 768, lg 1024, xl 1280).

Each name becomes a boolean in expressions:

VariableTrue when
breakpoint.smviewport.width >= 640 (and viewport is known)
breakpoint.mdviewport.width >= 768

Example — prefer breakpoints over raw width checks:

{
  "type": "when",
  "id": "layout",
  "condition": "{{ breakpoint.md }}",
  "then": { "type": "row", "id": "wide", "children": [ … ] },
  "else": { "type": "column", "id": "narrow", "children": [ … ] }
}

You can still mix viewport.* and breakpoint.* in one expression, e.g. {{ breakpoint.lg && viewport.orientation == 'landscape' }}.

qorm_inspect returns the effective breakpoints map for agents.

Client behaviour

On resize the inline script debounces a POST to /viewport {w,h}. The server re-renders (full render for viewport changes) and broadcasts over SSE. The client morphs the new HTML into #qorm-root, preserving focus and scroll where possible.

See also: /viewport in the HTTP API reference.