elm christmas

Elm and custom elements

←Previous postNext post →

The other javascript interop

A 4 min read written by
Harald Ringvold

Yesterday we saw how to do interop with javascript through ports for the times we need to do things that can not be done in Elm yet.

But there is another way! Instead of creating ports we can wrap our javascript code as a custom element.

What are custom elements?

Custom elements are a way to create your own HTML tags with you own content and behaviour. This is great for self contained UI widgets! We could for example use custom elements to display a spinner, a calendar or a code editor, all contained in one HTML tag.

Lets define a custom element called hello-world that outputs "Hello World!" in h1 tag:

customElements.define(
  'hello-world',
  class extends HTMLElement {
    connectedCallback() {
      this.innerHTML = '<h1>Hello World!</h1>';
    }
  }
);

We can use this as a normal HTML tag:

<hello-world></hello-world>

Custom elements are used as normal HTML tags but are often named with a hyphen to prevet naming collision with standard HTML tags.

Creating HTML tags in Elm

Before we go further we should take a look at how to create normal HTML tags in Elm. The Html module has functions for any tag you would need. Under you seeShown below are the type definitions for a couple of functions in the module.

div : List (Attribute msg) -> List (Html msg) -> Html msg
a : List (Attribute msg) -> List (Html msg) -> Html msg
span : List (Attribute msg) -> List (Html msg) -> Html msg
p : List (Attribute msg) -> List (Html msg) -> Html msg

You can probably see the similarities between these. All take a list of attributes and a list of other Html nodes and return a Html node.

div [ class "link-wrapper" ]
    [ a [href "https://elm-lang.org"] [ text "The Elm website"]
    ]

This Elm code produces the following HTML:

<div class="link-wrapper">
  <a href="https://elm-lang.org">The Elm website</a>
</div>

But how do we create HTML tags not found in the Html package? I'm glad you asked!

The Html package has the function node:

node : String -> List (Attribute msg) -> List (Html msg) -> Html msg

It is quite similar to the other functions except that it also takes a String. This is the name of the HTML tag you want to create. This function is in fact used to define all the HTML helper functions in the package. With this function we can create tags with any name we wish.

Using custom elements in Elm

And finally the good stuff! Now that we know a bit more about how HTML tags are created in Elm it is not so hard to use a custom element. Lets use the custom element hello-world we created earlier:

import Html

Html.node "hello-world" [] []

Yes, that is really it!

Limitations

There are some limitations to custom elements in general and some together with Elm spesifically so when using custom elements there are some recommendations:

  • Always use leaf nodes. Do not send HTML nodes as children to custom elements
  • Send all data to the custom elements as attributes
  • Dont use the attribute value as this is reserved in the Elm virtual DOM

Summary

It is relatively easy to use custom elements from Elm when you know a bit about how HTML is created in Elm. Custom elements are a great fit for UI widgets that need javascript libraries unavailable in Elm. The code editor in Ellie, an online Elm editor, is a great example.

Luke Westbys talk "When and how to use Web Components with elm" from Elm Europe 2018 is a great intro to custom elements in Elm and how it is used in Ellie and also explains a bit more on the limitations with custom elements in the context of Elm.

Custom Elements can also be a great way to reuse UI elements across applications written in different frameworks.

←Previous postNext post →