Skip to content
Logo

View constructors reference

This is the exhaustive reference for the view vocabulary. Start with Views for conceptual grounding; come here for exact signatures, render semantics, and the gaps each constructor closed.

The view types

Three levels, same structure:

TypeTyped message?Serializable?Use case
View MsgYes, fullyNoAuthoring with type safety; reflectView converts to RView
Ui MsgYes, fullyNoSimple proof specs; minimal vocabulary
RViewNo, defunctionalizedYesThe emitted, runtime-ready form

Minimal vocabulary

The original closed set. Every app uses at least these.

Constructor (Lean)SignatureRenders asNotes
textString → RViewStatic text contentA text node with no wrapper element
scalarString → RViewLive scalar valueThe current value of a named scalar field; re-renders on change
rowFieldString → RViewCurrent row's fieldUsed only inside a list item view; reads current_row[field_name]
inputString → RViewText input two-way boundBound to a named scalar; emits oninput handler without re-render
buttonString → String → Atom → RViewClickable buttonbutton label tag payload fires step(tag, payload) on click
listString → RView → RViewTable iteratorlist table item_view renders item_view once per row; row context active for rowField
colList RView → RViewContainer <div>Groups children; sets up grid layout context

Styled vocabulary

These carry inline CSS, so an entire product surface — chrome, shells, every screen — is UI-as-data with no hand-written render code downstream.

Constructor (Lean)SignatureRenders asNotes
rawString → RViewBare text nodeNo wrapper element; the text is emitted directly
elString → String → List RView → RViewCustom elementel tag style children — an arbitrary HTML element with inline style attribute
imgString → String → RView<img> tagimg src style — source URL and inline CSS
styledString → RView → RViewWrapped nodestyled style child wraps a single child with an inline style
btnString → String → String → Atom → RViewStyled buttonbtn label style tag payload — carries inline style; fires step(tag, payload) on click
clickString → String → Atom → List RView → RViewClickable containerclick style tag payload children — a styled <div> firing step(tag, payload) with the scalar payload, not the row
rowSelectString → String → List RView → RViewClickable list itemCloses gap G1: fires step(tag, ROW) with the whole current row as payload, so handlers can lift row fields to scalars with setFromRow (conversation selection, contact picking, etc.)
inpString → String → String → RViewStyled inputinp field placeholder style — text input with inline CSS, two-way bound to a named scalar field
rowFieldOrString → String → RViewRow field or fallbackrowFieldOr key fallback renders the row field, or the literal fallback string if the field is absent — used inside list

Lists and derived views

Render subsets or projections of a table without filtering the table itself.

Constructor (Lean)SignatureRenders asNotes
listWhereString → String → String → RView → RViewFiltered listCloses gap G2: listWhere table field scalarKey item renders item once per row where row[field] == scalars[scalarKey]. Keeps the full table intact; the view is the filter. Example: show messages for a selected conversation without modifying the messages table.
listDistinctString → String → RView → RViewGrouped listCloses gap G3: listDistinct table field item renders item once per distinct value of field, using the latest row with that value. Canonical for conversation lists and grouped feeds where you want one item per sender or per thread.
listOrEmptyString → RView → RView → RViewConditional tableCloses gap G11: listOrEmpty table item empty renders item once per row of table, or the empty view when the table is empty. Essential because empty states are real screens users see; a framework without this pushes authors into hand-written conditionals.

Conditionals

Branch on scalar or row-field values. Keep state-changing logic in handlers; keep appearance-changing logic here.

Constructor (Lean)SignatureRenders asNotes
condString → RView → RView → RViewTruthiness branchcond scalarKey then else branches on whether scalars[key] is truthy (non-null, non-false, non-zero, non-empty string)
condEqString → String → RView → RView → RViewEquality branchCloses gap G7: condEq scalarKey value then else branches on scalars[key] == value. Example: condEq "chat_type" "group" group_view dm_view
condFieldString → RView → RView → RViewRow field truthinesscondField field then else branches on the current row's field — used inside list items. Example: show "read" indicator only if the message is read.
condFieldEqScalarString → String → RView → RView → RViewRow-to-scalar equalityCloses gap G16: condFieldEqScalar field scalarKey then else branches on row[field] == scalars[key]. The canonical way to express "is this message mine?" as condFieldEqScalar "from" "identity" own_style others_style, because outgoing detection is from == identity

Advanced: arbitrary attributes and SVG

Constructor (Lean)SignatureRenders asNotes
elAttrString → List (String × String) → List RView → RViewElement with attributesCloses gap G10: elAttr tag attrs children renders an HTML element with arbitrary (key, value) attributes and children. The only constructor with an svg: namespaced attribute becomes an SVG element, enabling line-art icons as data. Example: elAttr "svg" [("svg:viewBox", "0 0 24 24"), ("svg:xmlns", "http://www.w3.org/2000/svg")] [elAttr "path" [("d", "M12 2L22 20H2Z")] []] renders an SVG triangle.

Ui — the minimal proven vocabulary

A simpler, four-constructor algebra used for proof specs and proof-tier view assertions.

inductive Ui (Msg : Type) where
  | text   : String → Ui Msg            -- static text
  | bind   : String → Ui Msg            -- render a named scalar
  | button : String → Msg → Ui Msg      -- button label and typed message
  | col    : List (Ui Msg) → Ui Msg     -- container
ConstructorRendersUse in proofs
textStatic textA fixed string assertion
bindLive scalar valueAssert that a scalar exists and render its value
buttonClickable buttonAssert that a handler fires
colContainerGroup children

Ui is intentionally minimal: the proof tier cares only about the message-bearing control points and their labels. Styling, layout, and derived views are the reflected (RView) layer's responsibility.

ViewDsl — authoring helpers

Generic aliases for RView constructors, shared by every app. These are thin wrapping functions with no proof impact — they are pure syntactic convenience.

namespace Encapp.ViewDsl
open Encapp
 
abbrev V := RView
 
def box (style : String) (cs : List V) : V := 
  .el "div" style cs
 
def span (style text : String) : V := 
  .el "span" style [.raw text]
 
def txt (style text : String) : V := 
  .el "div" style [.raw text]
 
def fld (key fallback : String) : V := 
  .rowFieldOr key fallback
 
def navTo (label style path : String) : V := 
  .btn label style "nav" (.str path)
 
def goTo (style path : String) (cs : List V) : V := 
  .click style "nav" (.str path) cs
 
def selectRow (style tag : String) (cs : List V) : V := 
  .rowSelect style tag cs
 
def scalar (k : String) : V := 
  .scalar k
HelperMaps toUse case
box style childrenel "div" style childrenA styled container div
span style textel "span" style [raw text]A styled inline text span
txt style textel "div" style [raw text]A styled block text div
fld key fallbackrowFieldOr key fallbackRender row field with literal fallback
navTo label style pathbtn label style "nav" (.str path)Navigate to path on click (fires the nav handler)
goTo style path childrenclick style "nav" (.str path) childrenClickable container that navigates
selectRow style tag childrenrowSelect style tag childrenRow-selecting list item (fires row payload)
scalar k.scalar kRender live scalar value

The nav handler is conventional — it sets the path scalar to navigate between pages. See Routing and gates.

View reflection and defunctionalization

reflectView : View Msg → RView converts authored View Msg (with typed Msg values) to serializable RView (with (tag, payload) pairs). The conversion is mechanical:

  • Every Msg value is defunctionalized to its tag : String and payload : Atom
  • Structure is preserved: an el in the source is an el in the output
  • All type safety is discharged at compile time
def reflectView : View Msg → RView

You use this when authoring a typed view : Model → View HMsg function. For mostly-layout screens with little typed logic, author directly in RView with ViewDsl helpers.

Rendering

The interpreter that runs the app is the interpreter that proves the test. Each platform has a renderer:

  • appDomJs (web) — maps every RView constructor to a DOM node; wires events to step
  • appRnJs (React Native) — maps the same constructors to RN elements

Both consume the identical appCoreJs state machine. test/native-core-identity.mjs asserts byte-identity of the two emitted cores. Style handling differs — web takes inline CSS directly, native parses them into RN style objects — which is why emitNative accepts base-style parameters for normalization.

Recap

  • Minimal vocabulary (text, scalar, rowField, input, button, list, col) is the foundation
  • Styled vocabulary adds inline CSS so UI-as-data covers the entire product
  • Derived view constructors (listWhere, listDistinct, listOrEmpty, conditionals) close specific gaps without extending the table algebra
  • elAttr is the escape hatch for arbitrary attributes and SVG
  • ViewDsl provides thin helpers over RView for common patterns
  • Ui is the proof-tier, minimal algebra; RView is the emitted form

Next steps

  • Views guide — conceptual overview and use patterns
  • App model — how to author view : Model → View Msg functions
  • Effects — the handler side of interaction