Core concepts

The View DSL

A VNode represents a DOM element — the most common kind of virtual DOM node. It carries a Namespace, a tag name, a list of Attribute values and a list of child Views.

The View type

The View is a rose tree of nodes, mutually recursive with Component through view:

data View context props model action
  = VNode Namespace Tag [Attribute model action] [View context props model action] DirectEvents
  | VText (Maybe Key) MisoString
  | VComp (SomeComponent context)
  | forall childProps. VCompStatic (StaticPtr (SomeStaticComponent childProps context)) childProps
  | VFrag (Maybe Key) [View context props model action]
  | VContext (context -> View context props model action)
  | VProps   (props   -> View context props model action)
  | VModel   (model   -> View context props model action)

data SomeComponent context
  = forall model action props. (Eq context, Eq model, Eq props)
  => SomeComponent (Maybe Key) props (Component context props model action)

VNode and VText map one-to-one onto the physical DOM. VComp and VFrag are abstract (they live only in the virtual DOM). The existential SomeComponent is what allows embedding polymorphic components in a View. VCompStatic carries a static pointer to its constructor and is used by the native dual-thread runtime.

VContext, VProps and VModel are not nodes at all, but accessors. Each wraps a function from the app-global context, the enclosing component's props or its model to a View. The function is applied and the wrapper discarded when the enclosing View is built or rendered, so none of the three ever reaches the diff. Build them with vcontext, vprops and vmodel — see Ambient accessors.

Element nodes

VNode HTML "div" [ HP.id_ "container" ] [ "Hello, world!" ]

In practice you rarely construct VNode directly. Use the element smart constructors from Miso.Html.Element, which fix the namespace and tag for you:

H.div_    [ HP.id_ "container" ]        [ "Hello, world!" ]
H.button_ [ HE.onClick DoSomething ]    [ "Click me" ]
H.h1_     [ HP.className "title" ]      [ text (ms pageTitle) ]

For elements not covered by Miso.Html.Element, use node (or its synonym vnode) directly:

node HTML "details" []
  [ node HTML "summary" [] [ "More info" ] ]

SVG and MathML elements use the SVG and MATHML namespaces and are covered by Miso.Svg.Element and Miso.Mathml.Element. Unlike VComp and VFrag, a VNode has a one-to-one correspondence with a physical DOM element.

node
raw constructor — namespace, tag, attributes, children
vnode
synonym for node
Miso.Html.Element
every HTML element (div_, span_, input_ …)
Miso.Svg.Element
SVG graphics, animation and container elements
Miso.Mathml.Element
MathML elements

Lifecycle hooks

Like components, elements expose lifecycle hooks:

  • onBeforeCreated
  • onCreated / onCreatedWith
  • onBeforeDestroyed / onBeforeDestroyedWith
  • onDestroyed

These are useful for initialising and tearing down third-party libraries, as in this example using highlight.js:

{-# LANGUAGE QuasiQuotes      #-}
{-# LANGUAGE MultilineStrings #-}

import Miso
import Miso.FFI.QQ (js)

data Action = Highlight DOMRef

update
  :: Action
  -> Effect context props model Action
update = \case
  Highlight domRef ->
    io_ [js| hljs.highlightElement(${domRef}) |]

view
  :: model
  -> View context props model Action
view _ =
  H.code_ [ onCreatedWith Highlight ]
    [ """
      function addOne (x) { return x + 1; }
      """
    ]

As a convention, the *With variant of a lifecycle hook (e.g. onCreatedWith) provides the target DOMRef to the callback.

The smart constructors, at a glance

node, vnode
build a VNode
text, vtext
build a VText — see Text nodes
component
build a VComp
fragment, vfrag, fragment_, vfrag_
build a VFrag
(+>)
key and mount a child Component
vcontext, vprops, vmodel
build a VContext, VProps or VModel — see Ambient accessors