Introducing stencil-elm-output-target, a plug-in for Stencil, a TypeScript-based toolchain for building web components:
React in TypeScript is nice. Elm is very nice. If you’re like us, you have a lot of both, and you need to build a sustainable component library for your design system. Web components to the rescue!
The problems with web components in React are well documented, but are also well solved by Stencil’s React Output Target, which auto-generates a React component with TypeScript types for each of your web components, that manages the interop between React’s events system and DOM events.
Web components in Elm have problems too:
- They provide no type-safe API out of the box
- Invoking methods on DOM nodes requires ports, which have friction (by design, as this buys you compiler guarantees)
- Component properties must be serializable as JSON (e.g. no functions)
This package seeks to solve as many of these problems as possible, by generating an Elm module for each of your Stencil components, that defines a type-safe API to use it in your Elm programs.
So instead of using a
stencil-button
element like this:view : Html Msg view = Html.node "stencil-button" [ Html.Attributes.attribute "variant" "primary" , Html.Events.on "buttonClick" (Json.Decode.succeed ButtonClick) ] [ Html.text "Click me" ]
you can import
Components.StencilButton
and have the compiler guarantee that you’re passing all the right attributes:import Components.StencilButton as StencilButton view : Html Msg view = StencilButton.view { variant = Just StencilButton.Primary , onClick = Just ButtonClick } [ Html.text "Click me" ]
The
StencilButton
module here is automatically generated by Stencil when you build your component library.Nice, right?
We’re looking forward to using this to enable our UI components to own just a little bit of their own view state when we want them to, and to being able to use them in both our Elm and React codebases (and who knows what else in the future!).
For a more detailed list of the supported component API features, and a description of the caveats of this initial version, check out the README.