# Surveying for interest in easier, type-safe custom elements tooling

**URL:** <https://discourse.elm-lang.org/t/surveying-for-interest-in-easier-type-safe-custom-elements-tooling/8678>\
**Category:** Request Feedback\
**Created:** [September 21, 2022, 3:32pm UTC](https://discourse.elm-lang.org/t/surveying-for-interest-in-easier-type-safe-custom-elements-tooling/8678 "2022-09-21T15:32:32Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![rjdellecese](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rjdellecese/32/4690_2.png) [@rjdellecese](https://discourse.elm-lang.org/u/rjdellecese)\
**Post date:** [September 21, 2022, 3:32pm UTC](https://discourse.elm-lang.org/t/surveying-for-interest-in-easier-type-safe-custom-elements-tooling/8678/1 "2022-09-21T15:32:32Z")

</div>

Hi everyone,

Custom elements in Elm offer a relatively safe way to utilize JavaScript libraries that expect to be able to manipulate some section of the DOM. But hooking them up to your Elm app can be finicky, requires a lot of annoying decoding/encoding work, and there aren’t that many good learning resources out there for how to do so.

In my work in the last few months, I’ve developed a small framework for managing custom elements in Elm and TypeScript, which includes type-safe interop between Elm and TS and a headless Elm architecture abstraction in TypeScript for each custom element. It has dramatically reduced the overhead for me of managing the interop between my custom elements in TS and their use and representation in Elm. I’ve used it for integrating [ProseMirror](https://prosemirror.net/), [CodeMirror](https://codemirror.net/), [Floating UI](https://floating-ui.com/), and [Viselect](https://github.com/Simonwep/selection) in my Elm app.

I don’t have it here to present to you today as a library—rather, I was hoping to get some sense of how useful other people think it might be so that I can gauge whether I ought to extract it from my app to share. So my questions for you are:

1. Does this sound like it would be useful to you?
2. If you use custom elements right now in your Elm app, how do you find the experience? What are the biggest pain points you’ve experienced?

I’m also happy to answer any questions about how this works and what problems I see it as solving.

Thank you!

---

<div class="post-metadata">

**Author:** ![wolfadex](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/wolfadex/32/2461_2.png) [@wolfadex](https://discourse.elm-lang.org/u/wolfadex)\
**Post date:** [September 21, 2022, 4:46pm UTC](https://discourse.elm-lang.org/t/surveying-for-interest-in-easier-type-safe-custom-elements-tooling/8678/2 "2022-09-21T16:46:21Z")

</div>

I’m very much interested in this and think it could be useful. We use a fair amount of web components at work and I use them frequently in my hobby Elm projects and making that process easier would be great.

1. Yes, it sounds useful
2. My biggest pain points right now wiring everything up and making sure I didn’t miss something

---

<div class="post-metadata">

**Author:** ![gampleman](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/gampleman/32/43_2.png) [@gampleman](https://discourse.elm-lang.org/u/gampleman)\
**Post date:** [September 22, 2022, 10:05am UTC](https://discourse.elm-lang.org/t/surveying-for-interest-in-easier-type-safe-custom-elements-tooling/8678/3 "2022-09-22T10:05:11Z")

</div>

This sounds great. I still think there is a need for better Elm specific documentation around custom elements ([I wrote a more specific list here](https://discourse.elm-lang.org/t/improved-documentation-for-flags-ports-and-custom-elements/5552/5)).

I’m curious what exactly your tooling offers? Generally in my experience the custom elements work is mostly twofold:

1. Doing a lot of minute work with DOM apis to get the java/type-script side to its job.
2. Doing fancy elm API design to put enough lipstick on the pig 🙂

The actual communication between these two modules tends to be a small minority of the code involved.

---

<div class="post-metadata">

**Author:** ![rjdellecese](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rjdellecese/32/4690_2.png) [@rjdellecese](https://discourse.elm-lang.org/u/rjdellecese)\
**Post date:** [September 23, 2022, 2:11am UTC](https://discourse.elm-lang.org/t/surveying-for-interest-in-easier-type-safe-custom-elements-tooling/8678/4 "2022-09-23T02:11:18Z")

</div>

> The actual communication between these two modules tends to be a small minority of the code involved.

That’s interesting to hear; my experience has been different! For my use of ProseMirror and CodeMirror, especially, there are lots of messages, with payloads, that need to be sent back and forth (and therefore decoded and encoded) between the Elm and the TS, which I’ve found to be a lot of work. What use cases have you run into for custom elements? Maybe they’ve involved less data interchange?

> I’m curious what exactly your tooling offers?

This tool would offer type-safe interop between the custom elements and Elm, and scaffolding for connecting the Elm representation of a custom element with the JS (TS, in our case) representation of it.

I did some API sketching today to better illustrate how it would work, which I’ll share below. This is a better and more generalized version of what I have right now, but is what I imagine extracting it into a library might look like.

* * *

# API Sketch

## Library code

> **CustomElement.elm**
>
> ```elm
> module CustomElement exposing (..)
> 
> type Model model
> 
> type Msg msg
> 
> define :
> { name : String
> , flagsCodec : Codec flags
> , toTsMsgCodec : Codec toTsMsg
> , toElmMsgCodec : Codec toElmMsg
> )
> -> { init : flags -> model
> , update : (toTsMsg -> Cmd msg) -> ( toElmMsg, model ) -> ( model, Cmd toElmMsg )
> }
> -> ( Definition flags toTsMsg toElmMsg model
> , { init : flags -> Model model
> , update : ( Msg toElmMsg, Model model ) -> ( Model model, Cmd (Msg toElmMsg) )
> , view : Model model -> Html (Msg toElmMsg)
> , send : toTsMsg -> Model model -> Cmd (Msg toElmMsg)
> }
> )
> 
> ```

> **custom-element.ts**
>
> ```ts
> export type Definition<Flags, ToTsMsg, ToElmMsg>
> 
> export type Registration
> 
> export const register: <Flags, ToTsMsg, ToElmMsg, Model>(
> definition: Definition<Flags, ToTsMsg, ToElmMsg>,
> init:
> (send: (toElmMsg: ToElmMsg) => void)
> => (htmlElement: HTMLElement)
> => (flags: Flags)
> => Model,
> update:
> (send: (toElmMsg: ToElmMsg) => void)
> => (htmlElement: HTMLElement)
> => (toTsMsg: ToTsMsg, model: Model)
> => Model,
> ) => Registration
> 
> export const init: (registrations: Registration[], elmApp: unknown) => void
> 
> ```

## App code

### Generated

> **generated/CustomElementPorts.elm**
>
> ```elm
> -- Contains the generated ports for interop.
> 
> ```

> **generated/custom-element-definitions.d.ts**
>
> ```ts
> // Contains the types for the custom element definitions defined in the Elm.
> 
> ```

### Usage

> **src/elm/CustomElementDefinitions.elm**
>
> ```elm
> -- This is where you expose all of your custom element definitions
> -- to the library CLI to parse and generate TS types from.
> 
> module CustomElementDefinitions exposing (customElementDefinitions)
> 
> import CustomElement
> import RichTextEditor
> 
> customElementDefinitions : List CustomElement.Definition
> customElementDefinitions =
> [RichTextEditor.customElementDefinition]
> 
> ```

> **src/ts/custom-elements/rich-text-editor.ts**
>
> ```ts
> import type { Registration } from "custom-elements";
> import type { richTextEditor } from "generated/custom-element-definitions"
> 
> type Model
> 
> const init:
> (send: (toElmMsg: richTextEditor.ToElmMsg) => void)
> => (htmlElement: HTMLElement)
> => (flags: richTextEditor.Flags)
> => Model
> 
> const update:
> (send: (toElmMsg: richTextEditor.ToElmMsg) => void)
> => (htmlElement: HTMLElement)
> => (toTsMsg: richTextEditor.ToTsMsg, model: Model)
> => Model
> 
> export const customElementRegistration: Registration
> 
> ```

> **src/index.ts**
>
> ```ts
> import customElements from "custom-elements";
> import richTextEditor from "src/ts/custom-elements/rich-text-editor";
> import { Elm } from "src/elm/Main";
> 
> const customElementRegistrations = [richTextEditor.customElementRegistration]
> const elmApp = Elm.Main.init()
> 
> customElements.init(customElementRegistrations, elmApp)
> 
> ```

---

<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:** [October 3, 2022, 2:11am UTC](https://discourse.elm-lang.org/t/surveying-for-interest-in-easier-type-safe-custom-elements-tooling/8678/5 "2022-10-03T02:11:35Z")

</div>

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