When working with elm you are not just working with the elm compiler but also with the virtual-dom. This speeds up rendering a lot but it's not a perfect. Sometimes it needs a bit of help. Below are two examples of were things go wrong and how to fix them.

Example 1

There is a html table where rows can be sorted based on a column. Suppose the table has just two rows. The action the virtual-dom has to do is look at the current situation (two rows) and the desired situation (two rows in different order). The virtual-dom is not going to traverse the children of the rows (which would be tds with their content). Therefor the start situation is the same as the end situation and the virtual-dom doesn't do anything.

Example 2

You have a div with some text and you want the user to be able to edit the text. You put an onClick handler on the div and on click you change the contents with an input box with the value of those same contents. When you change the text and click the input box again it resets to it's previous value. Why? Because to the virtual-dom the element where you set the click handler on (the div) didn't change, and so it doesn't remove the the handler even if you changed div in your code. So when the click event on the input happens it bubbles up to it's parent (the div) and the handler is triggered. To illustrate this a little further, this is the code:

-- when displaying
div [onClick address <| Edit Id] [text val]

-- when editing
div [] [ input [value val] [], button [] [text "save"] ]

The button does not have a click handler (as it should have for a save action), but this doesn't matter for the example. The important point to take away is in editing mode the onClick code is not there, and yet it does respond to the click event.


The solution is to mark the element with a special attribute that changes when the state changes. This is a small help to virtual-dom so that it doesn't have to inspect all it's children (and thus be much faster). In elm this is Html.Attributes.key (documentation here).

For the first example we could use a row id to set as key like this:

tr [Html.Attributes.key <| toString 1] [{-- children here--}]

For the second example we can do something similar.

  -- when displaying
  div [Html.Attributes.key "display", onClick address <| Edit Id] [text val]

  -- when editing
  div [Html.Attributes.key "edit"] [ input [value val] [], button [] [text "save"] ]

React, a very popular implementation for a virtual dom, describes this issue further in it's documentation