API to the core diffing algorithm. Can serve as a foundation for libraries that expose more helper functions for HTML or SVG.
An immutable chunk of data representing a DOM node. This can be HTML or SVG.
Just put plain text in the DOM. It will escape the string so that it appears exactly as you specify.
text "Hello World!"
Create a DOM node with a tag name, a list of HTML properties that can
include styles and event listeners, a list of CSS properties like
a list of child nodes.
import Json.Encode as Json hello : Node msg hello = node "div"  [ text "Hello!" ] greeting : Node msg greeting = node "div" [ property "id" (Json.string "greeting") ] [ text "Hello!" ]
Create a namespaced DOM node. For example, an SVG
<path> node could be
defined like this:
path : Array (Attribute msg) -> Array (Node msg) -> Node msg path attrubutes children = nodeNS "http://www.w3.org/2000/svg" "path" attributes children
When using HTML and JS, there are two ways to specify parts of a DOM node.
Attributes — You can set things in HTML itself. So the
<div class="greeting"></div>is called an attribute.
Properties — You can also set things in JS. So the
div.className = 'greeting'is called a property.
class attribute corresponds to the
className property. At first
glance, perhaps this distinction is defensible, but it gets much crazier.
There is not always a one-to-one mapping between attributes and properties!
Yes, that is a true fact. Sometimes an attribute exists, but there is no
corresponding property. Sometimes changing an attribute does not change the
underlying property. For example, as of this writing, the
attribute can be used in HTML, but there is no corresponding property!
Specify a style.
greeting : Node msg greeting = node "div" [ style "backgroundColor" "red" , style "height" "90px" , style "width" "100%" ] [ text "Hello!" ]
Create a property.
import Json.Encode as Encode buttonLabel : Node msg buttonLabel = node "label" [ property "htmlFor" (Encode.string "button") ] [ text "Label" ]
Notice that you must give the property name, so we use
htmlFor as it
for as it would appear in HTML.
behind the scenes.
buttonLabel : Node msg buttonLabel = node "label" [ attribute "for" "button" ] [ text "Label" ]
Notice that you must give the attribute name, so we use
for as it would
be in HTML, not
htmlFor as it would appear in JS.
Would you believe that there is another way to do this?! This uses
setAttributeNS function behind the scenes. It is doing pretty
much the same thing as
attribute but you are able to have namespaced
attributes. As an example, the
elm/svg package defines an attribute
xlinkHref : String -> Attribute msg xlinkHref value = attributeNS "http://www.w3.org/1999/xlink" "xlink:href" value
Create custom event handlers.
You can define
onClick like this:
import Json.Decode as Decode onClick : msg -> Attribute msg onClick msg = on "click" (Normal (Decode.succeed msg))
Note: These event handlers trigger in the bubble phase. You can learn more about what that means here. There is not support within Gren for doing tricks with the capture phase. We recommend doing that in JS through ports.
on you can customize the event behavior
a bit. There are two ways to do this:
stopPropagationmeans the event stops traveling through the DOM. So if propagation of a click is stopped, it will not trigger any other event listeners.
preventDefaultmeans any built-in browser behavior related to the event is prevented. This can be handy with key presses or touch gestures.
Note 1: A passive event listener will be created if you use
MayStopPropagation. In both cases
preventDefault cannot be used, so
we can enable optimizations for touch, scroll, and wheel events in some
Note 2: Some actions, like uploading and downloading files, are only
is for security! So when an event occurs, we call
update and send any
messages immediately, all within the same tick of the event loop. This makes
it possible to handle user-instigated events in ports.
Note 3: Normally the
view is shown in the next
call. This allows us to save some work if messages are coming in very quickly.
stopPropagation is used, we update the DOM immediately, within the
same tick of the event loop. This is useful for DOM nodes that hold their own
<input type="text">. If someone types very fast, the state in the
DOM can diverge from the state in your
Model while waiting on the next
requestAnimationFrame call. So updating the DOM synchronously makes this
This function is useful when nesting components with the Gren Architecture. It lets you transform the messages produced by a subtree.
Say you have a node named
button that produces
() values when it is
clicked. To get your model updating properly, you will probably want to tag
() value like this:
type Msg = Click | ... update msg model = case msg of Click -> ... view model = map (\_ -> Click) button
So now all the events produced by
button will be transformed to be of type
Msg so they can be handled by your update function!
Transform the messages produced by a
Works just like
node, but you add a unique identifier to each child
node. You want this when you have a list of nodes that is changing: adding
nodes, removing nodes, etc. In these cases, the unique identifiers help make
the DOM modifications more efficient.
Create a keyed and namespaced DOM node. For example, an SVG
could be defined like this:
g : Array (Attribute msg) -> Array ( String, Node msg ) -> Node msg g = keyedNodeNS "http://www.w3.org/2000/svg" "g"
A performance optimization that delays the building of virtual DOM nodes.
(view model) will definitely build some virtual DOM, perhaps a lot of
(lazy view model) delays the call until later. During diffing, we
can check to see if
model is referentially equal to the previous value used,
and if so, we just stop. No need to build up the tree structure and diff it,
we know if the input to
view is the same, the output must be the same!
lazy but checks on two arguments.
lazy but checks on three arguments.
lazy but checks on four arguments.
lazy but checks on five arguments.
lazy but checks on six arguments.
lazy but checks on seven arguments.
lazy but checks on eight arguments.