# Why is Html a single DOM node?

**URL:** <https://discourse.elm-lang.org/t/why-is-html-a-single-dom-node/3966>\
**Category:** Learn\
**Created:** [July 9, 2019, 5:23pm UTC](https://discourse.elm-lang.org/t/why-is-html-a-single-dom-node/3966 "2019-07-09T17:23:58Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![roberth](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/roberth/32/4473_2.png) [@roberth](https://discourse.elm-lang.org/u/roberth)\
**Post date:** [July 9, 2019, 5:23pm UTC](https://discourse.elm-lang.org/t/why-is-html-a-single-dom-node/3966/1 "2019-07-09T17:23:58Z")

</div>

Hi,

I was wondering about the Html type today. Do we have a compelling use case for the `Html a` as opposed to `List (Html a)`? In which cases do we really care that our argument is a single DOM node?

The reason to ask the question is because if we generally don’t care, the `html` library (or a wrapper?) can define its `Html` type to always represent a list of DOM nodes. The benefit is that can simplify types, that you don’t have to pick and that you certainly don’t need meaningless wrapper `div`s.

I’ve done a bit of research. The `http` library only has `Html a` in argument position on one function, which is `map`. Judging from that, such a refactoring seems feasible. At least two other areas remain: low-level details and HTML semantics.

I don’t really expect performance to change that much, because `html` is dealing with a lot of lists anyway. However, I don’t know how it’s implemented, so I really can’t judge this.

Regarding HTML semantics, at first I thought `html` has to be by itself, but is that really a requirement? For the DOM API it is, so probably it does make sense to have it as a low level type at least.

`Browser` has the `element` function which takes an `Html a` so that’s a use case. (what happens if I insert a text node in `element`? 😈)

So my question is, which APIs or even elements did I miss? Do you want to enforce single DOM nodes in certain cases?

Update: naming idea: `Node` for DOM nodes and `Html` for multiple `Node`s. Consider it a mass noun.

Update:

- it makes the type signatures align with expectations from other APIs (thanks @pdamoc)

---

<div class="post-metadata">

**Author:** ![pdamoc](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/pdamoc/32/36_2.png) [@pdamoc](https://discourse.elm-lang.org/u/pdamoc)\
**Post date:** [July 10, 2019, 7:24am UTC](https://discourse.elm-lang.org/t/why-is-html-a-single-dom-node/3966/2 "2019-07-10T07:24:26Z")

</div>

Hi @roberth and welcome to the Elm community.

> [@roberth](#):
>
> Do we have a compelling use case for the `Html a` as opposed to `List (Html a)` ?

I’m confused a little bit. When you are talking about the `Html a` nodes defined in the `Html` library, how do you propose to declare the attributes of those nodes in your alternative?

For example, what would `button [onClick Increment][text "+"]` look like in your proposal?

---

<div class="post-metadata">

**Author:** ![roberth](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/roberth/32/4473_2.png) [@roberth](https://discourse.elm-lang.org/u/roberth)\
**Post date:** [July 10, 2019, 7:49am UTC](https://discourse.elm-lang.org/t/why-is-html-a-single-dom-node/3966/3 "2019-07-10T07:49:00Z")

</div>

Hi @pdamoc,

It would look the same. You’d have

```
text : String -> Html msg

button : List (Attribute msg) -> Html msg -> Html msg

button [onClick Increment] (text "+") : Html msg

```

The button function gets all the information to construct the button, as before.

A big difference why this can be done in Elm `html` and not in many other libraries is because `html` doesn’t have any setter functions to modify an element. In fact it can not even have setters because you can’t set an attribute on a text node.

`html` would have `concat` function, `none : Html msg` and a `++` operator would be really nice.

Update: `empty` -\> `none`

---

<div class="post-metadata">

**Author:** ![pdamoc](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/pdamoc/32/36_2.png) [@pdamoc](https://discourse.elm-lang.org/u/pdamoc)\
**Post date:** [July 10, 2019, 7:57am UTC](https://discourse.elm-lang.org/t/why-is-html-a-single-dom-node/3966/4 "2019-07-10T07:57:01Z")

</div>

I find it very confusing to have the type of an `HTMLElement` be the same as the type of its children.

I’m trying to understand what would the benefit of your approach be. I’m also trying to understand what problem are you actually trying to solve here with this redesign.

---

<div class="post-metadata">

**Author:** ![roberth](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/roberth/32/4473_2.png) [@roberth](https://discourse.elm-lang.org/u/roberth)\
**Post date:** [July 10, 2019, 8:08am UTC](https://discourse.elm-lang.org/t/why-is-html-a-single-dom-node/3966/5 "2019-07-10T08:08:29Z")

</div>

The real-world problem that this solves is the need for meaningless `div []` to turn `List (Html msg)` into `Html msg` because someone wrote a function that has an `Html msg` parameter.

This also means that the community doesn’t have to teach newcomers to always write `List (Html msg)` parameters instead of `Html msg`. I think Elm does a good job of making it easy to do “The Right Thing”, but this stands out to me.

I agree that the type of `element` is a slightly less descriptive with this change, but I don’t think that’s a problem. The difference between “a list of nodes” and “more HTML” seems insignificant to me.

---

<div class="post-metadata">

**Author:** ![pdamoc](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/pdamoc/32/36_2.png) [@pdamoc](https://discourse.elm-lang.org/u/pdamoc)\
**Post date:** [July 10, 2019, 8:24am UTC](https://discourse.elm-lang.org/t/why-is-html-a-single-dom-node/3966/6 "2019-07-10T08:24:57Z")

</div>

> [@roberth](#):
>
> The real-world problem that this solves is the need for meaningless `div []` to turn `List (Html msg)` into `Html msg`

If someone’s function expects a node, give it a node. I think this is perfectly fine to wrap a list with `div []`

If you don’t like to have an extra div and would have preferred that that function receives a list, you are free to reimplement it to match your preference.

> [@roberth](#):
>
> This also means that the community doesn’t have to teach newcomers to always write `List (Html msg)` parameters instead of `Html msg` .

A `List` of children should look like a `List`. It is less surprising to see `List (Html msg)` than to discover that an element is actually a list.

> [@roberth](#):
>
> The difference between “a list of nodes” and “more HTML” seems insignificant to me.

It might be so for you but the difference between “a list of nodes” and “a node” is significant. It is easier to model mentally an HTMLElement to one thing than to a list.

If you really want to avoid extraneous divs, feel free to delay the construction of the container. In other words, have your functions return `List (Html msg)` and concatenate them like this :

```auto
firstPart : Model -> List (Html Msg) 
firstPart model = 
    ...

secondPart : Model -> List (Html Msg)  
secondPart model = 
    ...

someSection : Model -> Html msg 
someSection model = 
    section [] ( firstPart model ++ secondPart model )

someSectionAlt : Model -> Html msg 
someSectionAlt model = 
    [ firstPart model 
    , secondPart model 
    ...
    , lastPart model 
    ]
    |> List.concat
    |> section []

```

---

<div class="post-metadata">

**Author:** ![roberth](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/roberth/32/4473_2.png) [@roberth](https://discourse.elm-lang.org/u/roberth)\
**Post date:** [July 10, 2019, 11:08am UTC](https://discourse.elm-lang.org/t/why-is-html-a-single-dom-node/3966/7 "2019-07-10T11:08:47Z")

</div>

Indeed I have become more inclined to just use `List (Html msg)` in most parameters now and doing so works.

Your example illustrates this approach nicely.

It also has an interesting typo. You wrote `List msg` because you were thinking about lists instead of HTML.

---

<div class="post-metadata">

**Author:** ![pdamoc](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/pdamoc/32/36_2.png) [@pdamoc](https://discourse.elm-lang.org/u/pdamoc)\
**Post date:** [July 10, 2019, 12:33pm UTC](https://discourse.elm-lang.org/t/why-is-html-a-single-dom-node/3966/8 "2019-07-10T12:33:53Z")

</div>

> [@roberth](#):
>
> It also has an interesting typo. You wrote `List msg` because you were thinking about lists instead of HTML.

Good catch. I have updated the code to the correct form.

---

<div class="post-metadata">

**Author:** ![1hko](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/1hko/32/1328_2.png) [@1hko](https://discourse.elm-lang.org/u/1hko)\
**Post date:** [July 10, 2019, 1:24pm UTC](https://discourse.elm-lang.org/t/why-is-html-a-single-dom-node/3966/9 "2019-07-10T13:24:10Z")

</div>

> [@roberth](#):
>
> It also has an interesting typo. You wrote `List msg` because you were thinking about lists instead of HTML.

What kind of voodoo did I just witness? If this doesn’t make a compelling point, I don’t know what does 😅

This is a great question and discussion so far.

@roberth I think the primary reason `List` is used is because Elm functions cannot have a variadiac interface. A parameter can only be bound to a single value, but that value could indeed be a list containing multiple values.

Using your proposed change to the API, how would you represent this Html unordered list?

- one
- two

```elm
ul [] (li [] (text “one”))

```

Where should we insert `li [] (text “two”)`?

Using `List a` is the way for us to understand that a function accepts a variadic (0 or more) number of `a`-typed elements. As much as I love your idea to allow the programmer to forget such complexity, I believe this is a limitation in the language itself - Ie, there’s no way to express a variadiac interface in a language where all functions are curried and lists (or other compound data types) are the only option for specifying a variable number of arguments.

(This is also the reason we sometimes see things like `map2`, `map3`, … `map9`)

---

<div class="post-metadata">

**Author:** ![roberth](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/roberth/32/4473_2.png) [@roberth](https://discourse.elm-lang.org/u/roberth)\
**Post date:** [July 10, 2019, 1:40pm UTC](https://discourse.elm-lang.org/t/why-is-html-a-single-dom-node/3966/10 "2019-07-10T13:40:17Z")

</div>

An `Html msg` type is (conceptually) still appendable and appending still has a neutral element (like `[]` but named `Html.none`). One might even say it’s a Monoid (/me takes cover). So ideally it’s like

```
ul [] (
  li [] (text one ++ text one) ++
  li [] (text b)
)

```

Is it ok to overload `++`?

Instead of overloading `++` we might define `Html` as a type alias `type alias Html msg = List (HtmlNode msg)`.

---

<div class="post-metadata">

**Author:** ![Jess\_Bromley](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/jess_bromley/32/3396_2.png) [@Jess\_Bromley](https://discourse.elm-lang.org/u/Jess_Bromley)\
**Post date:** [July 11, 2019, 12:17am UTC](https://discourse.elm-lang.org/t/why-is-html-a-single-dom-node/3966/11 "2019-07-11T00:17:38Z")

</div>

I think [elm-ui](https://package.elm-lang.org/packages/mdgriffith/elm-ui/1.1.0/) resolves this problem by highlighting the semantic differences. Most elements can _only_ have one child and so only take another `Element msg` as an argument. Those that have multiple children (and so take `List (Element msg)`) do so for a reason made obvious in their name, e.g. `Element.row` or `Element.column`. Not only does this make it much easier to work out which you need to hand to a given element, but what you have and what the element expects are more often than not already the right thing anyway. If you haven’t looked at it, it’s definitely worth checking out…

---

<div class="post-metadata">

**Author:** ![roberth](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/roberth/32/4473_2.png) [@roberth](https://discourse.elm-lang.org/u/roberth)\
**Post date:** [July 11, 2019, 8:27am UTC](https://discourse.elm-lang.org/t/why-is-html-a-single-dom-node/3966/12 "2019-07-11T08:27:51Z")

</div>

@Jess_Bromley, elm-ui seems to provide a really good ‘language’ to describe user interfaces.

> This library is a complete alternative to HTML and CSS.

Sadly that’s too big a change for us right now, because it’s very compelling.

HTML semantics seem to embrace its “rose tree” format and always provide some meaning for the juxtaposition of siblings. `elm-ui` doesn’t seem to leave that meaning implicit and only defines it for elements that have the explicit purpose of combining elements, such as `row`. Interestingly, it does define `Element.none`, so `Element msg` seems to be a bit like `Maybe (Html msg)` (where `Html` has the usual definition).

---

<div class="post-metadata">

**Author:** ![popara](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/popara/32/719_2.png) [@popara](https://discourse.elm-lang.org/u/popara)\
**Post date:** [July 16, 2019, 8:58pm UTC](https://discourse.elm-lang.org/t/why-is-html-a-single-dom-node/3966/13 "2019-07-16T20:58:59Z")

</div>

I think you make couple of good points that can be formulated in alternative UI library.

Problem is that `Html` by it self is not inspectable, so you can’t ask does this div has 4 children? Oh plug one element after second child.

That would maybe get some jQuery smell in elm ,but i don’t know, I may use it couple of times, especially if you realize that you have taken the wrong path in structuring your solution, and deadline is screaming DEPLOYIT!!

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/1X/50a05e53677a2c3b47776d7abd0f113eb50193a1.png) [@system](https://discourse.elm-lang.org/u/system)\
**Post date:** [July 26, 2019, 9:03pm UTC](https://discourse.elm-lang.org/t/why-is-html-a-single-dom-node/3966/14 "2019-07-26T21:03:34Z")

</div>

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.
