Karl Herrick

A technologist and web developer | Posts about technology encountered along the journey.

The Web Is Dynamic

HTML, JavaScript, and CSS are key parts of the Open Web Platform as they assist in creating customized, yet reusable solutions that anyone might need to build high quality, robust web applications, without requiring unnecessary complexity.

In this small example, a few support libraries work together to provide efficient templating, as well as an implementation of React’s Hooks API, allowing us to use state of the art features, while still preserving compatibility with the wider ecosystem on the Web.

With the addition of script:

(async () => {
  const { html } = await import('https://unpkg.com/lit-html@^1.0.0/lit-html.js')
  const { component, useState } = await import('https://unpkg.com/haunted@4.7.1/haunted.js')

  function counter({ value }) {
    const [count, setCount] = useState(value);
    const handleSetCount = (val) => () => {
      setCount(val);
      this.setAttribute("value", val);
    };

    return html`
      <style>
        span {
          margin: var(--x-hook-component-span-margin, inherit);
        }
      </style>
      <button
        type="button"
        @click=${handleSetCount(isNaN(count) ? 0 : Number(count) - 1)}
      >
        Decrement
      </button>
      <span id="count">${count}</span>
      <button
        type="button"
        @click=${handleSetCount(isNaN(count) ? 0 : Number(count) + 1)}
      >
        Increment
      </button>
    `;
  }

  if (!customElements.get("x-hook-component")) {
    customElements.define(
      "x-hook-component",
      component(counter, { observedAttributes: ["value"] })
    );
  }
})()

Some basic styles included:

x-hook-component {
  --x-hook-component-span-margin: 0 2rem;

  align-items: center;
  background: #2b2b2b;
  color: #fff;
  display: flex;
  justify-content: center;
  margin: 1rem 0;
  padding: 1rem;
}

And the element rendered (with a default value included even), we can define new and interesting behavior without much trouble at all.

<x-hook-component value="5"></x-hook-component>

Being that custom elements and dynamic import are so widely supported now — adding functionality and content in this way is starting to make a lot more sense for many use cases — especially seeing how once loaded and cached, the cost to reload any support libraries seems barely noticeable. Try this example on CodeSandbox.