Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Using React inside Elm

Register Element

First you will need document-register-element

yarn add document-register-element

Add script to register elements

Create a JS function to register React Components as Custom elements. See registerCustomElement.js below

Register the elements

e.g. HelloComponentCustomElement.jsx

import registerCustomElement from "registerCustomElement"

function HelloComponent(props) {
  return (
    <div>Hello</div>
  )
}

registerCustomElement(CustomComponent, "hello-component")

Import this script in your app

e.g. in App.js

// Custom Elements
import "app/widgets/HelloComponentCustomElement.jsx"

Use the custom element in Elm

e.g. in View.Elm

node "hello-component" [ attribute "some-prop" encodedJsonValue ] []
// @flow
// Adapted from https://github.com/bspaulding/react-custom-element
import "document-register-element"
import bows from "bows"
import React from "react"
import ReactDOM from "react-dom"
import rollbar from "shared/services/rollbar"
const log = bows("registerCustomElement")
function render(ComponentClass: React$ComponentType<any>) {
return function() {
const attributesCopy = [].slice.call(this.attributes)
const props = attributesCopy.reduce((attrs, attr) => {
attrs[attr.nodeName] = attr.nodeValue
return attrs
}, {})
ReactDOM.render(
<ComponentClass {...props} />, this
)
}
}
function detach() {
ReactDOM.unmountComponentAtNode(this)
}
function created() {
// Flow requires createdCallback
}
// TODO: Type ComponentClass properly
function registerCustomElement(ComponentClass: any, tagName: string) {
const elementPrototype = Object.create(HTMLElement.prototype)
elementPrototype.attachedCallback = render(ComponentClass)
elementPrototype.attributeChangedCallback = render(ComponentClass)
elementPrototype.detachedCallback = detach
elementPrototype.createdCallback = created
try {
return document.registerElement(tagName || ComponentClass.displayName, {
prototype: elementPrototype,
})
} catch(e) {
rollbar.error(e)
}
}
export default registerCustomElement
@domenkozar
Copy link

domenkozar commented Nov 3, 2021

Thanks, I needed to fix two things:

  • CustomComponent should be called HelloComponent
  • registerCustomElement.js should be named registerCustomElement.jsx

It will also fail if any style is set on the elm node

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment