# Print unescaped HTML

**URL:** <https://discourse.elm-lang.org/t/print-unescaped-html/4635>\
**Category:** Learn\
**Created:** [November 8, 2019, 11:31am UTC](https://discourse.elm-lang.org/t/print-unescaped-html/4635 "2019-11-08T11:31:06Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![jan2100](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/jan2100/32/2858_2.png) [@jan2100](https://discourse.elm-lang.org/u/jan2100)\
**Post date:** [November 8, 2019, 11:31am UTC](https://discourse.elm-lang.org/t/print-unescaped-html/4635/1 "2019-11-08T11:31:06Z")

</div>

I’m converting an element of an already built webapp to use Elm. I have all the functionallity needed except printing unescaped HTML in a paragraph but I haven’t found a way to do it.

The source of the data I want to print is trustworthy so no worries for js injection and whatnot.

So my question is how should I achieve this?

---

<div class="post-metadata">

**Author:** ![bruchmann](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/bruchmann/32/3683_2.png) [@bruchmann](https://discourse.elm-lang.org/u/bruchmann)\
**Post date:** [November 8, 2019, 12:19pm UTC](https://discourse.elm-lang.org/t/print-unescaped-html/4635/4 "2019-11-08T12:19:32Z")

</div>

There’s a discussion about this at [elm#172](https://github.com/elm/html/issues/172).

---

<div class="post-metadata">

**Author:** ![jreusch](https://avatars.discourse-cdn.com/v4/letter/j/b5e925/32.png) [@jreusch](https://discourse.elm-lang.org/u/jreusch)\
**Post date:** [November 8, 2019, 12:38pm UTC](https://discourse.elm-lang.org/t/print-unescaped-html/4635/5 "2019-11-08T12:38:08Z")

</div>

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

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

```

(see [here](https://github.com/elm/virtual-dom/blob/master/src/VirtualDom.elm#L167) and [in the Kernel Code](https://github.com/elm/virtual-dom/blob/master/src/Elm/Kernel/VirtualDom.js#L289))

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:

```auto
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:

```auto
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 🙂

[https://ellie-app.com/78LvFwt5xWpa1](https://ellie-app.com/78LvFwt5xWpa1)

---

<div class="post-metadata">

**Author:** ![dmy](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/dmy/32/702_2.png) [@dmy](https://discourse.elm-lang.org/u/dmy)\
**Post date:** [November 8, 2019, 12:48pm UTC](https://discourse.elm-lang.org/t/print-unescaped-html/4635/6 "2019-11-08T12:48:34Z")

</div>

You could use [hecrj/html-parser](https://package.elm-lang.org/packages/hecrj/html-parser/latest/):

```auto
module Main exposing (main)

import Html exposing (Html)
import Html.Parser
import Html.Parser.Util

main : Html msg
main =
    Html.div [] <|
        case Html.Parser.run "<h1>Header</h1><p>A paragraph with <b>bold</b> text.</p>" of
            Ok html ->
                Html.Parser.Util.toVirtualDom html

            Err err ->
                [Html.text (Debug.toString err)]

```

[https://ellie-app.com/78VdLqGMSWda1](https://ellie-app.com/78VdLqGMSWda1)

If you really trust the input (as it will not be sanitized) and the size overhead is acceptable (or you already use it in the application), you could also use `elm-explorations/markdown` with `sanitize = False`, because HTML is valid markdown:

```auto
main : Html msg
main =
    Markdown.toHtmlWith
        { githubFlavored = Nothing
        , defaultHighlighting = Nothing
        , sanitize = False
        , smartypants = False
        }
        []
        "<h1>Header</h1><p>A paragraph with <b>bold</b> text.</p>"

```

[https://ellie-app.com/78VfdLnfbw5a1](https://ellie-app.com/78VfdLnfbw5a1)

I would use a web component if performance was critical and I would most likely use something like [DomPurify](https://github.com/cure53/DOMPurify) or [sanitize-html](https://github.com/apostrophecms/sanitize-html) anyway (trusted input can become untrusted later or because of a vulnerability).

---

<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:** [November 18, 2019, 12:48pm UTC](https://discourse.elm-lang.org/t/print-unescaped-html/4635/7 "2019-11-18T12:48:40Z")

</div>

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