Other authoring layers
Template components are the authoring form that renders on the server and hydrates. Two other layers build DOM in the browser: authored views, which construct each instance's DOM during mounting, and Fable.Ranvier, a small library of DOM helpers.
Authored views
An authored view is a Program.View: a function over the mount's backend. Generated.Html.Program holds a constructor for each of the 112 HTML elements, Generated.Html.Attrs and the per-element modules hold modifiers, and Ranvier.View.Dom.Authoring holds text, components, keyed arrays, branches and boundaries.
open global.Ranvier
open Ranvier.View
open Ranvier.View.Dom.Authoring
module H = Ranvier.View.Dom.Generated.Html
module Html = Ranvier.View.Dom.Generated.Html.Program
module Attr = Ranvier.View.Dom.Generated.Html.Attrs
let rowsView (rows: Signal<(int * string) array>) : Program.View =
Html.section
[| Attr.classStatic "rows" |]
[|
Html.button
[|
H.Button.onClick (fun _ ->
let next = rows.Value.Length + 1
rows.Value <- Array.append rows.Value [| next, "Item " + string next |])
|]
[| text "Add row" |]
keyedArray fst (fun () -> rows.Value) (fun current ->
Html.div [| Attr.idStatic ("row-" + string (fst (current ()))) |] [| reactiveText (fun () -> snd (current ())) |])
|]
| Function | Meaning |
|---|---|
text value, reactiveText read | Fixed and tracked text. |
fragment children | Children in order. |
createComponent setup props | A component whose setup runs once per mounted instance. |
keyedArray key read render | Keyed rows; each row's render receives a reader of its current item. |
branch key read render | One instance, kept while its key is equal under =. |
boundary pending failed content | A boundary over authored views. |
Ranvier.View.Dom.Generated.Html requires qualified access; alias it as above. Generated.Html.Authoring adds overloaded Attrs and Props modules for the authored layer, whose members accept a value, a unit -> 'T reader, a Signal<'T> or a Memo<'T>. Keep that open out of files that open the sugar.
Run an authored view in a mount with Program.run view context.Backend, the same call that runs Component.render. A static snapshot comes from Representation.Html.render, written in full beside the Html alias:
let snapshot (rows: Signal<(int * string) array>) : string =
Ranvier.View.Representation.Html.render Omit (Program.run (rowsView rows))
<section class="rows"><button>Add row</button><div id="row-1">Alpha</div></section>
Authored views inside templates
A template embeds a Program.View through a view hole, t.view:
open Ranvier.View
open Ranvier.View.Sugar
type Card = { Caption: string; Body: Program.View }
let card =
Component.define (fun _ (card: Card) -> card) (fun t ->
div (Attrs.className "card") {
h3 () { fun c -> c.Caption }
t.view (fun c -> c.Body)
})
The reader runs once per instance, untracked. The server writes the view between region markers; hydration mounts a view hole fresh between those markers rather than adopting its nodes, and an authored component's CreateId issues ids that can differ between server and client.
Fable.Ranvier
src/Fable.Ranvier is a proof-of-concept library of DOM helpers. Nodes are created with ordinary F# functions, and each binding is one Ranvier effect:
open Fable.Core.TS.Dom
open global.Ranvier
open Fable.Ranvier
let graph = new Graph ()
let count = graph.Run (fun () -> createSignal 0)
let host = Global.document.getElementById("app").Value
let mounted =
Mount.mount graph host (fun () ->
Dom.element "button"
[ Dom.on "click" (fun _ -> count.Value <- count.Value + 1) ]
[ Dom.reactiveText (fun () -> $"Count: {count.Value}") ]
:> Node)
Mount.mount graph host factoryappends the factory's single root node and returns anIDisposablethat removes the node and stops its bindings and listeners.- Event handlers are batched by default: the DOM updates once when the handler's batch finishes.
Mount.mountWith { DomOptions.Default with Scheduling = Microtask } graph host factoryalso defers DOM writes to a microtask.
The library has static child structure only: lists, conditional content, server rendering and hydration belong to template components. Its README documents each helper and the scheduling options.