Custom Elements in Elm

Hello

  • I’m Luke
  • I work at NoRedInk
  • I’m a member of the Elm core team
  • I made Ellie

Interop

  • No more Native code
  • The only way to interoperate with the platform is via the platform
  • ports from the Elm side
  • The Web APIs from the JS side

Ports

  • Actor model
  • Fully async
  • Map directly to imperative APIs
  • What about the view?

View Interop

Example

  • Google Maps
  • Scaling overhead is high

View Interop Needs

  • “Proprietary” views
  • Performance-critical visuals
  • Required synchronous reactions
  • Ancillary local state
  • Browser hacks!

Solution: “use the platform”

Custom Elements

customElements.define('my-tag-name', class extends HTMLElement {
  constructor() {
    super()
    // initialize
  }
  
  // intercept changes to _properties_ on an element in JS
  get something() { /* ... */ }
  set something(value) { /* ... */ }
  
  attributeChangedCallback(name, previous, next) {
    // intercept changes to _attributes_ on a tag in the HTML
  }
  
  connectedCallback() {
    // called when the element has been fully inserted into the DOM
  }
  
  disconnectedCallback() {
    // called when the element has been fully removed from the DOM
  }
})

Custom Elements

  • Reusable and distributable
  • Fully encapsulated

Html.node

  • Html.node : String -> List (Attribute msg) -> List (Html msg) -> Html msg
  • Exposed by elm-lang/html
  • Allows you to create any kind of HTML node you can express
  • Custom elements registered after a tag has been inserted into the DOM will upgrade those existing nodes

Example

Benefits

  • No restrictions on what you can render in Elm as an HTML element
  • Fully allowed by Elm’s restrictions
  • No direct management with ports
  • Allows for expressing nice, declarative APIs over imperative JS engines

Issues

Big issue: VirtualDom awareness

  • VirtualDom attempts to reuse elements
  • Virtual Dom can mistake one element for another even if they are internally different
  • Use Html.keyed to protect an element
  • Expose every changeable aspect through an Attribute so the diff can check them
  • VirtualDom is the source of truth for children
  • Differences in the children VirtualDom is aware of and that exist in the DOM can cause overwrites
  • Always use empty children [] or a static list that your custom element does not modify

Small issue: Browser support

  • Ready in latest Chrome and Safari on desktop and mobile
  • Edge is expected to start development soon
  • Polyfill for Firefox and IE11/Edge

In Production

  • NoRedInk
  • Ellie
  • Maybe others IDK yet