Print unescaped HTML

So, the official answer here is to use Web Components.

Please take everything of the following with a grain of salt, since it technically breaks guarantees and security features of Elm. It might even stop working at the next patch release of elm/virtual-dom.


There is a really simple but hackish way to avoid Web Components (and their polyfills and dependencies), if all you want to do is render a static HTML string from your Elm app.

Elm specifically checks for the property name innerHTML to prevent you from defining something like

innerHTML : String -> Attribute msg
innerHTML = Json.Encode.string >> Html.Attributes.property "innerHTML"

(see here and in the Kernel Code)

There is a very simple way to get around this limitation, if we could just use a different property other than “innerHTML” though!

Using Object.defineProperty, you can provide an arbitrary getter function instead of having a real backing field. We can use this to define a proxy-property for innerHTML on the HTMLElement “class” with a different name:

Object.defineProperty(HTMLElement.prototype, "mcHammerInnerHTML", {
    get () {
        return this.innerHTML
    },
    set (value) {
        this.innerHTML = value
    }
})

With this we can work-around the protective measures (against XSS attacks) the Elm Virtual DOM enforces:

innerHTML = Json.Encode.string >> Html.Attributes.property "mcHammerInnerHTML"

-- [...]

div [ innerHTML "<b>Can</b> touch this!" ] []

And there you go! You have your innerHTML property back. Your mileage may vary, and if you are not careful, the Virtual DOM may override your stuff, or break entirely. You have been warned :slight_smile:

https://ellie-app.com/78LvFwt5xWpa1

4 Likes