# Does Elm have a reflective HTML package?

**URL:** <https://discourse.elm-lang.org/t/does-elm-have-a-reflective-html-package/6584>\
**Category:** Request Feedback\
**Created:** [November 30, 2020, 3:56pm UTC](https://discourse.elm-lang.org/t/does-elm-have-a-reflective-html-package/6584 "2020-11-30T15:56:37Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [November 30, 2020, 3:56pm UTC](https://discourse.elm-lang.org/t/does-elm-have-a-reflective-html-package/6584/1 "2020-11-30T15:56:37Z")

</div>

And would it benefit from having one?

The problem is, that `elm/virtual-dom` `Node` is opaque:

> **[VirtualDom - virtual-dom 1.0.2](https://package.elm-lang.org/packages/elm/virtual-dom/latest/VirtualDom#Node)**

So when you get some user-defined view customization, lets say its some UI framework you are writing, and you wanted the user to supply their own `Markdown -> Html` function

```auto
addMarkdown : (Markdown -> Html Never) -> View -> View
addMarkdown userCustomization view =

```

You may want to parse that user defined Html for some reason.

Perhaps not the best example. In my case, I am interested in offering the ability to render custom views for my text editor work. I need to be able to understand the structure of the user customized view, in order to do coordinate mapping for the cursor - to understand how the cursor moves through that section of the DOM.

A reflectice HTML package would define a non-opaque node type, and a function to turn it into an `elm/virtual-dom` `Node`:

```auto
type ReflectiveNode = 
    Element String (List Attribute) (List Element)

toNode : ReflectiveNode -> Node

```

The idea would be to create a full DSL as an exact parallel to the `elm/html` API, just in a different module name-space.

Disadvantage is, there is obviously an overhead when rendering HTML, and it its a novel HTML representation with no connection to existing packages like `elm-css`, or `elm-ui`.

Does such a package already exist? Are there other use cases that it could be useful for?

---

<div class="post-metadata">

**Author:** ![theotherben](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/theotherben/32/2186_2.png) [@theotherben](https://discourse.elm-lang.org/u/theotherben)\
**Post date:** [November 30, 2020, 10:01pm UTC](https://discourse.elm-lang.org/t/does-elm-have-a-reflective-html-package/6584/2 "2020-11-30T22:01:54Z")

</div>

I have a use case for this!

We’d like to be able to render a “minimap” or “preview” view of our page, while making sure that there are no `id`s in the minimap render (otherwise you’d have duplicate IDs!). The two approaches we’ve thought of so far are:

1. Passing some sort of configuration value down the entire `view` call chain.
2. Creating a custom element that strips out `id` from anything inside of it.

A non-opaque node type would be a much better solution!

---

<div class="post-metadata">

**Author:** ![Sebastian](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/sebastian/32/98_2.png) [@Sebastian](https://discourse.elm-lang.org/u/Sebastian)\
**Post date:** [December 1, 2020, 2:56am UTC](https://discourse.elm-lang.org/t/does-elm-have-a-reflective-html-package/6584/3 "2020-12-01T02:56:52Z")

</div>

We use [https://package.elm-lang.org/packages/zwilias/elm-html-string/2.0.2/](https://package.elm-lang.org/packages/zwilias/elm-html-string/2.0.2/) for rendering html into a string sometimes, we pass that to a JS tooltip library.

Something like this would be nicer as you could hook different renderers at the very end.

---

<div class="post-metadata">

**Author:** ![allanderek](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/allanderek/32/1360_2.png) [@allanderek](https://discourse.elm-lang.org/u/allanderek)\
**Post date:** [December 1, 2020, 9:44am UTC](https://discourse.elm-lang.org/t/does-elm-have-a-reflective-html-package/6584/4 "2020-12-01T09:44:12Z")

</div>

It’s not exactly a use case of being able to _inspect_ a node, but I’ve found the inability to add attributes to a previously computed node leads to code that might be more complicated than it would otherwise. A simple example, suppose you want all of the buttons on your site to be styled with one of 3 classes, you might do something like:

```auto
type ButtonClass
     = Primary
      | Secondary
      | Danger

button : ButtonClass -> msg -> Html msg
button bClass message =
        ... defined in the obvious way ...

```

Maybe you define this in a `Site` module, so whenever you need a button you call `Site.button` and you are guaranteeing that all the buttons on your site have exactly one of the three button classes. You could even in theory write an elm-review rule to avoid direct use of `Html.button`.

Now suppose you want a button that is disabled, in that case you’re forced to take that in as a parameter to `Site.button`, because there is no: `addAttribute : Attributes msg -> Node msg -> Node msg`. Then maybe you find a case where you want to give some button an ‘id’, again you’re going to have to add that in as a parameter. Generally I find that my attempts to write such ‘helper’ functions go awry in this fashion and I end up either abandoning it, or I just take a list of attributes into `Site.button`. Alternatively I just have a `buttonClass : ButtonClass -> Attribute msg` helper function.

Perhaps I’m missing a way in which this is helping me, but it **feels** as if I’m being forced into more complicated/awkward code than otherwise.

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [December 1, 2020, 10:07am UTC](https://discourse.elm-lang.org/t/does-elm-have-a-reflective-html-package/6584/5 "2020-12-01T10:07:04Z")

</div>

> [@Sebastian](#):
>
> We use [https://package.elm-lang.org/packages/zwilias/elm-html-string/2.0.2/](https://package.elm-lang.org/packages/zwilias/elm-html-string/2.0.2/) for rendering html into a string sometimes, we pass that to a JS tooltip library.
> 
> Something like this would be nicer as you could hook different renderers at the very end.

Yes, that is also a use case for covering server side rendering as well as client side. You could write a view in the reflective HTML, then render to String or to `elm/html`.

---

<div class="post-metadata">

**Author:** ![gampleman](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/gampleman/32/43_2.png) [@gampleman](https://discourse.elm-lang.org/u/gampleman)\
**Post date:** [December 1, 2020, 11:32am UTC](https://discourse.elm-lang.org/t/does-elm-have-a-reflective-html-package/6584/6 "2020-12-01T11:32:33Z")

</div>

I’ve bee thinking about this, but taking it further. I was inspired by the Effect pattern in the sense that a really nice\* architecture for Elm apps is to build a custom runtime. Currently that mostly relies on a custom `Effect` type, but one could also have a custom `View` type. This `View` type could be composed out of higher level elements out of a design system plus elm-ui style layout primitives:

```elm
type View msg
     = Button ButtonStyle msg String
     | Tabset String (List (String, View msg))
     | Column (Attrs msg) (List (View msg))
     | Row (Attrs msg) (List (View msg))
     -- ...

```

Then the runtime would be be responsible for transforming these into HTML. I imagine this would have the following benefits:

1. Testing would be simpler, since asserting that a view renders with a particular tab selected is just pattern matching, rather than requiring some specialised library.
2. Some of the components could be stateful, but the state could be hidden from the caller.
3. Renderers could be swapped. A custom renderer could be an interesting solution for responsivety for example, but why not render your website directly to PDF?
4. Reflectivity (as above).

Of course I have no idea how bad the performance penalty would be. Also it’s not clear how mitigation strategies like `lazy` could be supported in this scheme.

---

<div class="post-metadata">

**Author:** ![glasserc](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/glasserc/32/2611_2.png) [@glasserc](https://discourse.elm-lang.org/u/glasserc)\
**Post date:** [December 1, 2020, 3:54pm UTC](https://discourse.elm-lang.org/t/does-elm-have-a-reflective-html-package/6584/7 "2020-12-01T15:54:45Z")

</div>

I haven’t used it myself, but I did notice [https://package.elm-lang.org/packages/ThinkAlexandria/elm-html-in-elm/latest/](https://package.elm-lang.org/packages/ThinkAlexandria/elm-html-in-elm/latest/) the other day.

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [December 3, 2020, 9:28am UTC](https://discourse.elm-lang.org/t/does-elm-have-a-reflective-html-package/6584/8 "2020-12-03T09:28:08Z")

</div>

> [@theotherben](#):
>
> We’d like to be able to render a “minimap” or “preview” view of our page, while making sure that there are no `id` s in the minimap render (otherwise you’d have duplicate IDs!).

You got me thinking, if there were a phantom type parameter, then things like this could even be enforced by the compiler:

```elm
type alias ReflectiveHtml msg a = 
    ReflectiveNode msg a

type ReflectiveNode msg a =
   ...

type ReflectiveAttribute msg a = 
   ...

type Always
    = Always

id : String -> ReflectiveAttribute msg { hasId : Always }

stripIds : ReflectiveHtml msg a -> ReflectiveHtml msg { hasId : Never }

minimap : ReflectiveHtml Never { hasId : Never } -> Model -> (Html Msg, Html Msg)

```

That `minimap` function accepts a caller defined view that is guaranteed to have no ids in it and the compiler is enforcing a check on that.

However… it would mean an extra type parameter, and I was thinking to keep the API exactly as the `Html.Html` API is, for familiarity and ease of swapping existing code to/from reflective.

Perhaps there could be 2 APIs, one with phantom types, and one without? Same implementation under-the-hood, the one without just fills in a dummy value.

```auto
module Reflective.Html exposing (..)

import Reflective.Phantom.Html

type alias Html msg = 
    Reflective.Phantom.Html.Html msg ()

```

Trouble is thats a type alias, so pattern matching would not work directly on it, you would need to work with the phantom version for that. 🤔

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [December 3, 2020, 9:29am UTC](https://discourse.elm-lang.org/t/does-elm-have-a-reflective-html-package/6584/9 "2020-12-03T09:29:56Z")

</div>

> [@glasserc](#):
>
> I haven’t used it myself, but I did notice [https://package.elm-lang.org/packages/ThinkAlexandria/elm-html-in-elm/latest/](https://package.elm-lang.org/packages/ThinkAlexandria/elm-html-in-elm/latest/) the other day.

A useful reference for implementation. As mentioned above, I was thinking to go with an API that is 1:1 with `elm/html` for familiarity and swappability. Wonder why this package did not also do that?

I think this will be worth doing, not sure when I will be able to make a start on it, but its definitely in the pipe-line.

---

<div class="post-metadata">

**Author:** ![berend](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/berend/32/2250_2.png) [@berend](https://discourse.elm-lang.org/u/berend)\
**Post date:** [December 3, 2020, 8:45pm UTC](https://discourse.elm-lang.org/t/does-elm-have-a-reflective-html-package/6584/10 "2020-12-03T20:45:55Z")

</div>

> [@rupert](#):
>
> Does such a package already exist? Are there other use cases that it could be useful for?

This design is heavily used in [elm-mdc](https://github.com/aforemny/elm-mdc). So you can add/change attributes. Only at the last minute things are turned into the virtual dom node.

---

<div class="post-metadata">

**Author:** ![ChristophP](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/christophp/32/1528_2.png) [@ChristophP](https://discourse.elm-lang.org/u/ChristophP)\
**Post date:** [December 6, 2020, 11:15pm UTC](https://discourse.elm-lang.org/t/does-elm-have-a-reflective-html-package/6584/11 "2020-12-06T23:15:38Z")

</div>

I really love the effect pattern to keep effect more transparent and avoid passing things like API tokens around unnecessarily. I could see a similar approach work with the view with the necessary libraries. One would need a drop-in Html replacement kinda like elm-css has though I assume.

---

<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:** [December 16, 2020, 11:15pm UTC](https://discourse.elm-lang.org/t/does-elm-have-a-reflective-html-package/6584/12 "2020-12-16T23:15:39Z")

</div>

Closed on December 16, 2020, 11:15pm UTC

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