Skip to content

Hicasso glossary

This glossary defines Hicasso-specific terms. Core re-frame2 terms such as app-db, frame, event, and subscription live in the core glossary.

Authoring

Hicasso

re-frame2's native React view adapter. Hicasso interprets Hiccup, reads subscriptions with h/sub, and accepts event vectors as intents. App-db, events, effects, and the event pipeline remain ordinary re-frame2.

Require it as:

[re-frame.hicasso :as h]

Forms, overlays, routing helpers, the native tier, and test tooling are separate optional namespaces.

Related: Getting started, Installation.

defview

h/defview defines a Hicasso view. The view receives one props map and returns Hiccup, nil, a fragment, or a native React element at the direct-return performance level.

Use a view as a Hiccup head. Do not call it as an ordinary function:

(h/defview counter [_]
  [:main
   [:h1 "Clicked " (h/sub [:counter/count]) " times"]
   [:button {:on-click [:counter/increment]}
    "Click me"]])

[counter {}]   ;; view boundary
(counter {})   ;; raises

Related: Views and reads.

View

A function from a props map to markup, defined with h/defview. In Hiccup head position it creates an independently re-rendering boundary. A plain defn is an inline helper, not a view.

Related: Views and reads.

Boundary

An independently re-rendering unit created by h/defview. It:

  • tracks the body's h/sub reads;
  • compares props with ClojureScript =;
  • supplies the re-frame2 frame used by event intents.

Native tags, fragments, and h/defhost heads do not create Hicasso view boundaries.

Related: Views and reads.

Inline helper

An ordinary function called from a view body. Its returned Hiccup is included in the caller's tree, and any h/sub calls belong to the enclosing boundary. It does not create independent re-render behaviour.

[todo-row {:key id :id id}]   ;; child boundary
(row-icon {:kind :urgent})    ;; inline helper

A plain function in Hiccup head position raises :rf.error/hicasso-bad-head.

Related: Views and reads.

h/sub

The only subscription-read form inside a Hicasso view. It is an ordinary function call and may appear in a let, conditional, loop, or synchronous helper.

(let [todo (h/sub [:todo/by-id id])]
  [:span (:title todo)])

A bare rf/subscribe in a view body is not an alternative. Native components use n/use-sub.

Related: Views and reads.

Read-extent law

h/sub is legal only during direct synchronous execution of the active view body, including helpers it calls immediately. A callback, promise, timer, lazy sequence, unforced delay, or other deferred computation may not carry the read outside that extent.

A read after the extent raises a structured error such as :rf.error/hicasso-sub-outside-render or :rf.error/hicasso-deferred-read-at-boundary. Read the value during render and close over the value instead.

Related: Views and reads.

Collector

The runtime mechanism that records the subscriptions a boundary reads during one body execution. Commit reconciles that read set. An abandoned or retried render acquires no durable subscription ownership.

Related: Views and reads.

Component ABI

The props and children contract for a Hiccup head: which values are converted, which pass by identity, where :key and :ref live, and how children arrive.

  • Hicasso views receive a ClojureScript props map.
  • Declared hosts follow their callback, slot, and server contracts.
  • Native n/$ uses React slots and does not lower Hicasso event intents or controlled fields.

Related: Views and reads, Interop, The native tier.

Lowering

The conversion from Hicasso data to React props and elements. It includes the Hiccup walk, event-intent callback creation, controlled-field behaviour, and attribute normalisation.

When diagnostics identify lowering itself as the cost owner, the local escape is a direct n/$ return from the same view.

Related: Events as data, The native tier.

Owned-wins merge

When a view forwards an attributes map into an element, literal keys written by the element author take precedence. Control slots such as :value, handlers, :key, and ::h/revision should not be replaceable through a generic forwarded map.

Related: Views and reads, Controlled inputs.

Read topology

The placement and grouping of subscription reads relative to a collection.

Shape Behaviour
Fine Each row reads its own entity; good for sparse updates
Coarse One view-model represents the collection; good for cheap mount or bulk replacement
Chunked One read covers a bounded block of rows
Windowed Only visible rows exist in the DOM, usually through a virtualiser

Related: Lists and collections.

Events and control

Intent

An event vector written directly at an event prop. The runtime creates a callback and dispatches the vector into the rendering view's frame.

[:button {:on-click [:todo/toggle id]}
 "Toggle"]

The Hiccup tree retains the event as ordinary data, so tests and tools can inspect it with =.

Related: Events as data.

h/event

The one marked callback form (HD-024). Expands to an ordinary function. The contract comes from the position where it is written: event positions dispatch a returned vector; render positions must stay pure; unclaimed host props refuse the mark.

[:input {:type "file"
         :on-change (h/event [e]
                      [:upload/picked
                       (js/Array.from (.. e -target -files))])}]

Captures the rendering frame when created. Use it when arguments determine the event — value-first foreign callbacks, file lists, drag data — or when the body must call browser methods such as .preventDefault.

Related: Events as data, Interop.

h/frame

Returns the frame id keyword of the Hicasso boundary currently rendering. Legal only during a boundary body or a render callback that boundary supplied. Not a tracked subscription.

Exported today as h/hframe; substitute that spelling to run the sample below. The difference is deliberate and is recorded under Status.

The taught carry spelling is composition with core:

(let [{:keys [dispatch]} (rf/capture-frame (h/frame))]
  )

Zero-arity ambient (rf/capture-frame) refuses under Hicasso's body discipline. Prefer effects for application async work; use this at foreign edges that retain a dispatching closure.

Related: Events as data.

::h/value and ::h/checked

Reserved markers replaced at dispatch with the event target's current value or checked state. Substitution occurs only at the top level of the event vector.

::h/value is the target's .value on every control but one. A <select multiple>'s value is its selection rather than a scalar, so the marker carries a vector of the selected option values — [] when nothing is picked. Reading .value there would answer the first selected option only, which is a plausible string that quietly is not what the user chose.

[:input
 {:value    (h/sub [:draft])
  :on-input [:draft/changed ::h/value]}]

Related: Events as data, Controlled inputs.

::h/prevent

An intent wrapper that calls preventDefault and then dispatches one inner event vector. Hicasso does not auto-prevent clicks; :on-submit is the one position whose data spelling prevents by default, so a submit intent needs no wrapper. A callback always owns its own event and is never auto-prevented.

[:a.nav-link
 {:href      "#"
  :on-click  [::h/prevent [:todo/filter-active]]}
 "Active"]

Related: Events as data.

Controlled field

An input whose displayed value comes from app-db and whose user edits return as event intents. Hicasso's controlled path provides:

  • synchronous same-turn convergence;
  • committed-value echo;
  • caret and selection preservation;
  • IME composition safety;
  • explicit reset through ::h/revision.

The native tier does not provide this repair. Keep controlled text fields on the interpreted Hicasso path.

Related: Controlled inputs.

::h/revision

A reserved prop for controlled text. Change it when the field should re-baseline to the current model value after a reset, rejection, rewrite, or server normalisation.

[:input
 {:value       (h/sub [:field/value id])
  ::h/revision (h/sub [:field/revision id])
  :on-input    [:field/edit id ::h/value]}]

Reset is not inferred from value equality. The exact namespaced keyword is required; bare :revision is an ordinary attribute.

Related: Controlled inputs.

Buffered field

forms/buffered-field is an optional forms component that places an app-db draft in front of a controlled model value. It supports commit, cancel, rejection, rewrite, and revision-based reset.

Related: Forms.

Keyboard map

A map from DOM .key strings to event intents, used at :on-key-down or :on-key-up.

{:on-key-down
 {"Enter"  [:editor/commit]
  "Escape" [:editor/cancel]}}

Unlisted keys are ignored. There is no modifier DSL; use h/event for cases such as Ctrl+Enter. Key maps suppress matches during IME composition.

Related: Events as data.

Interop

defhost

h/defhost declares a foreign React component once. The declaration can define:

  • callback contracts: :event, :handler, or :render;
  • ReactNode slots;
  • a server policy;
  • a Client-only fallback.
(h/defhost date-picker DatePicker
  {:callbacks {:on-change :event}
   :slots     #{:calendar}
   :server    :client-only})

Keep the JavaScript require in a .cljs host namespace.

Related: Interop.

ReactNode slot

A host prop declared to contain React content, such as a modal title, footer, or Suspense fallback. Hiccup supplied to the slot is converted to React elements under the captured frame. Undeclared props receive Hiccup vectors as ordinary data.

Related: Interop.

as-element

h/as-element explicitly converts Hiccup to a React element for a render prop, foreign callback, or other ReactNode position.

{:render-item
 (fn [row]
   (h/as-element
    [row-view {:id (:id row)}]))}

Related: Interop, Lists and collections.

as-component / outward bridge

h/as-component turns a Hicasso view into a real React component that a native React, UIx, or JavaScript parent can mount under the existing frame provider. It does not create another root or state owner.

Related: Interop.

Portal

h/portal renders Hiccup into another DOM container through React createPortal while preserving frame and context. React events bubble through the React tree rather than the DOM placement.

Use the overlay module instead when the UI should live on the browser's native top layer.

Related: Interop, Overlays and focus.

Server policy

The SSR contract for a host or native component:

  • Render: execute on the server and produce deterministic React HTML;
  • Client-only: do not execute on the server; produce a deterministic fallback or nothing until the browser adopts the root.

Foreign hosts and named native components default to Client-only. Native Hiccup and intrinsic React elements render by default.

Related: SSR and hydration, Interop.

Raw escape (:>)

[:> Component props ...] mounts a foreign React component without a lasting host declaration. It is useful for migration or a true one-off. Repeated crossings should use h/defhost so callback contracts, slots, and server policy remain explicit.

Related: Interop.

Native tier

Native tier

The optional re-frame.hicasso.native namespace, usually aliased n. It provides direct React element construction and named native components.

[...] always means interpreted Hiccup. n/$ always means native React. Nothing silently compiles or promotes one form into the other.

Related: The native tier.

n/$

A macro that constructs one React element directly. It does not perform Hiccup lowering, intent conversion, class collection merging, controlled-field repair, or automatic Hiccup-child conversion.

(n/$ :td {:class "px"} px)
(n/$ :td (n/props cell-props) px)

Use h/as-element when one native subtree needs an interpreted Hiccup child.

Related: The native tier.

n/props

A syntactic marker telling n/$ that a dynamic expression is its props operand. It creates no runtime wrapper.

Without the marker, an arbitrary dynamic map in second position is treated as a child.

Related: The native tier.

n/defcomponent

Defines a named top-level React function component with Hicasso's native-tier marker, source identity, display name, and server policy. Ordinary React hooks are legal inside it.

Use n/use-sub and n/use-frame to join the current re-frame2 frame.

Related: The native tier.

n/use-sub

A React hook that subscribes to a re-frame2 query in a native component. It obeys React's rules of hooks: call it unconditionally at the top level of the component.

Related: The native tier.

n/use-frame

A React hook returning frame-locked operations such as :dispatch, :dispatch-sync, and :subscribe for the current native component.

Related: The native tier.

Native island

A named native React component under the same React root and re-frame2 frame as the surrounding Hicasso application. It is appropriate for hooks, vendor widgets, and high-rate host-private mechanics.

Xray names and times the crossing, while the inner React tree remains host-opaque.

Related: The native tier.

n/memo

Marker-preserving React memoisation for a named native component. Raw react/memo can erase the marker used by Xray and embedding checks.

Related: The native tier.

n/lazy

Marker-preserving React.lazy loading for a named native component. It follows React's promise-returning loader contract and retains the Hicasso native marker. Declare it at namespace top level.

Related: Code splitting and lazy loading, The native tier.

Performance ladder

Five explicit implementation levels:

  1. ordinary Hicasso;
  2. tuned read topology;
  3. a direct native return from an existing view;
  4. a named native island;
  5. a native screen.

Related: Performance, The native tier.

Escape-benefit rule

Keep a native escape only when it:

  • recovers at least 20% of the measured interaction;
  • saves at least 2 ms at p95; or
  • converts a failed user-visible budget into a pass.

Otherwise remove it.

Related: Performance.

State homes

One state owner

Application-visible state lives in re-frame2 app-db. Hicasso does not add a component-local reactive store. A host may retain private mechanics only when they are not a hidden duplicate of an application fact.

Related: Ephemeral state.

motion/presence

Optional exit-retention head from re-frame.hicasso.motion. Keeps keyed children for :timeout-ms after their data leaves app-db so CSS exit transitions can run. Applies ::h/mounting / ::h/unmounting attribute overrides on elements, or passes :rf/phase to view children. Not an animation system.

Related: Motion and presence, Ephemeral state.

Pressure valve

A legitimate home for UI state under the one-state-owner rule:

  • an explicit app-db address;
  • the forms module for drafts and form control;
  • native host state for high-rate private mechanics;
  • browser-owned state as an explicit interop choice;
  • presence retention for pixels that outlive removed data.

Related: Ephemeral state.

Overlay

re-frame.hicasso.overlay popover and modal primitives. They use the browser's native top layer. App-db owns :open?; :on-dismiss is an event; the browser owns stacking, light-dismiss, modal focus trapping, and focus restoration.

A closed overlay has no DOM node, listener, or active body subscriptions.

Related: Overlays and focus.

A routing helper that returns a real anchor and encodes navigation as a Hicasso intent. It supports route ids and params, optional intent prefetch, native link semantics, and link-local veto behaviour.

It is an inline function, not a separate view. Active-state styling comes from a route subscription comparison.

Related: Routing and navigation.

View-scoped read

A resource whose lifetime is a local view rather than the current route. It has no dedicated mechanism: the event that decides the data is wanted ensures it under an owner, and the event that dismisses the view releases that owner.

(rf/reg-event :suggestions/wanted
  (fn [_ [_ q]]
    {:fx [[:dispatch [:rf.resource/ensure
                      {:resource :app/suggestions
                       :params   {:q q}
                       :owner    [:suggestions]
                       :cause    [:suggestions/wanted q]}]]]}))

Resource subscriptions are passive in every case — they project the cache and never fetch. An owner pins its entry against GC until it is released.

Related: Async resources, Resources glossary.

Testing

Test kit

Two namespaces:

  • re-frame.hicasso.test, usually ht, for pure and semantic tests;
  • re-frame.hicasso.test.mounted, usually hm, for mounted React and DOM tests.

Related: Testing.

Testing ladder

Level Proves Mechanism
L0 Handlers, subscriptions, transitions Pure function calls
L1 Intents, codecs, revision laws, macro expansion Data and property tests
L2 One hook-free body as a semantic tree ht/tree
L3 React lifecycle, hooks, hosts, error boundaries Mounted facade
L4 IME, caret, focus, hydration, performance Real browser engines

A lower level does not prove the equality of a higher level.

Related: Testing.

Semantic harness

ht/tree runs one hook-free Hicasso view body with injected subscription fixtures and returns a semantic tree. Nested views remain represented as calls. Hooks, hosts, raw React elements, and n/$ results are refused and belong at L3.

Related: Testing.

Mounted facade

The hm namespace for L3 tests. It provides isolated-frame mount and hydrate, rerender, dispatch-and-settle, settle, virtual-clock advancement, unmount, and assert-clean! residue checking.

Related: Testing.

Sabotage control

A deliberately broken twin of an important test or measurement. It proves that the instrument moves when the input is wrong and prevents an empty population from passing vacuously.

Related: Testing.

Canonical DOM

A normalised DOM serialisation used for differential comparison. Attribute names are ordered so equivalent DOM does not differ only because properties were inserted in a different sequence.

Canonical DOM is distinct from semantic-tree equality, exact server bytes, and hydrated browser behaviour.

Related: Testing, Migrating from Reagent.

Diagnostics

Causal lens

The diagnostic sequence used by Xray:

event
  → subscriptions recomputed
  → values changed
  → views notified
  → bodies run
  → React commit
  → browser paint

Render, commit, and paint are separate claims.

Related: Diagnostics.

Explain-render

Xray's answer to “why did this view run?” It reports the cause category, changed reads or props, current read set, fan-out, completeness, and evidence loss.

Related: Diagnostics.

Hot-view advisor

A diagnostic ranking that combines time, frequency, read churn, and fan-out, then classifies the pressure as computation, topology, lowering, React, or layout. It recommends the smallest credible remedy and never auto-promotes code to native.

Related: Diagnostics, Performance.

Loss labels

Explicit labels for incomplete evidence:

  • :unknown;
  • :opaque / :no-static-analysis;
  • :host-opaque;
  • :cap;
  • :uncorrelated.

Missing evidence is not represented as an empty result.

Related: Diagnostics.

Complaint catalogue

The stable :rf.error/* and :rf.warning/* identifier set, including cause, recovery, and source links where available. Tests assert the id, not the human message.

Related: Diagnostics.

Production erasure

Removal of development diagnostics, evidence machinery, source locations, and complaint messages from default release bundles. Optional performance timing has a separate compile-time flag and is disabled by default.

Related: Diagnostics.

Lifecycle and delivery

mount!, render!, and unmount!

The Hicasso root lifecycle.

h/mount! associates a DOM container, a frame, optional :initial-events, and one root view. It returns a root handle. Initial events run in order before first paint.

h/render! renders a new root element through the same handle.

h/unmount! tears the root down and is safe to call more than once.

(defonce root
  (h/mount!
   (js/document.getElementById "app")
   {:frame :rf/default
    :initial-events [[:app/init]]}
   [app-shell {}]))

Related: Installation.

hydrate!

Two functions complete hydration:

  • re-frame.ssr/hydrate! installs the server payload into the client frame;
  • h/hydrate! adopts existing server DOM for one Hicasso root.

State hydration must run before DOM adoption.

Related: SSR and hydration.

Error boundary

h/error-boundary is a React error region with :fallback, :reset-key, and :on-error. It is different from a re-render boundary; only the error boundary catches descendant render and lifecycle exceptions.

Expected failures remain ordinary app-db state.

Related: Errors.

User-visible budget

A performance requirement expressed as an observable user outcome, such as:

  • discrete interaction paint within 50 ms p95;
  • controlled echo within one frame;
  • broad operation within 100 ms p95;
  • zero teardown residue.

Synthetic benchmark scores do not replace these budgets.

Related: Performance.

Shadow comparison

A migration witness that mounts a reference implementation and candidate under isolated equivalent state, drives both with one script, and compares canonical DOM plus event-intent streams at each checkpoint.

Related: Migrating from Reagent.