DEV Community

Cover image for Shoemaker: an elegant way to create web components

Shoemaker: an elegant way to create web components

claviska profile image Cory LaViska Updated on ・4 min read

Component-driven development is all the rage these days, and users of React, Vue, Angular, and many other frameworks will be instantly familiar with what a component is in the context of web development.

The fact is, there are many flavors of components out there and many great libraries that offer entire collections of them. But at the end of the day, a React component will only work in React and a Vue component will only work in Vue.

That's where web components can help.

I know, I know. I've heard it plenty of times before: "web components suck!" If you've never worked with them before, or if you've only worked with them using the low-level custom elements API, I won't fault you for thinking that. But hear me out.


I think the distaste many folks have for web components stems from a simple misunderstanding. The APIs collectively know as "web components" weren't intended to replace your favorite framework. As with most things that become part of the standard, these are lower level APIs that will be supported for a long, long time. They were given to us with the hope that we'd build great tools around them, which we have with Stencil, lit-element, hybrids, Haunted, and so many more.

"If you need to use a tool to build them, why not just use a framework?"

Because, unlike your favorite framework, these tools all have one thing in common: they produce custom HTML elements that work everywhere!

  • In HTML/JS
  • In frameworks (more info)
  • With components created in other tools

To be clear, I'm not telling you to stop using frameworks — but there's only so many times you can create the same "button" component in React, Vue, Angular, et al before you start to think, "maybe there's a better way?"

If we can agree on that, we can probably also agree that certain components, such as those in your design system, might be better off as web components so they can be used throughout your organization without forcing everyone into the same framework.

I've seen a very positive result from users of, an open source library of web components I maintain, because they can use it with or without a framework (and because they don't have to write many of these basic components themselves).

Choose Your Flavor

Here's the thing about web components. You can pick whatever tool you want to create them with! Are you a fan of Typecript + JSX? You'll probably really like Stencil. Do you prefer working with hooks in React? Give Haunted a go.

You have the freedom to create highly reusable components with whatever opinionated tooling you want without forcing those opinions onto other teams. That is, consumers will see and use your components for what they are: HTML elements!

I'm somewhat of a web standards purist, or at least I try to be when it makes sense, so being able to create custom HTML elements is an amazing concept to me. It wasn't long after I started experimenting with many of these tools that I started to think, "what's my flavor of web components?"

Introducing Shoemaker

One day, I opened VS Code and started working on a new component. I wasn't using any tools — just a blank editor. I created the syntax I wanted based on my experience as a front-end engineer and a web components enthusiast. Then I opened another tab and hacked it into existence.

The result is a tool I'm calling Shoemaker.

I think every single framework/compiler/tool shows an obligatory counter example, so I'll do the same:

import { Shoemaker, html } from '@shoelace-style/shoemaker';

export class MyCounter extends Shoemaker {
  static tag = 'my-counter';
  static props = ['count'];

  count = 0;

  render() {
    return html`
      <button type="button" onclick="${() => this.count++}">
        Count: ${this.count}

MyCounter.register(); // now you can use <my-counter></my-counter> in your HTML
Enter fullscreen mode Exit fullscreen mode

Try it in CodePen

At the core of Shoemaker is an abstract class that you can extend to create a custom element. You can use the resulting element in plain HTML or with your favorite framework.


Shoemaker is designed to be lightweight and stick to the platform as closely as possible. It uses template literals powered by uthml for fast, efficient rendering with no virtual DOM requirement.

Shoemaker weighs in at just under 7 KB gzipped, but it packs some powerful features:

  • An elegant API
  • Declarative templates
  • Reactive data binding via props + state
  • Fast, efficient rendering
  • Intuitive lifecycle hooks
  • Watchers
  • Works with and without TypeScript

One really cool thing about this project is that you can load it directly from a CDN. This makes it really easy to whip up new custom elements without worrying about a build system.

And, of course, it's open source!

In fact, the code is right here on GitHub so feel free to take a look.


February 23, 2021 – this utility was originally called "Sushi Element," but it was renamed and has become a part of the open source suite.

Discussion (1)

Editor guide
hnrq profile image
Henrique Ramos

Nice! Sushi Element is a great name! I still have a lot to learn about Web Components API, but I'll definitely give SE a shot 😊