What & Why

JS

import UIElement from '@efflore/ui-element';

customElements.define('show-appreciation', class extends UIElement {
  static observedAttributes = ['count'];

  attributeMapping = { count: 'integer' };

  connectedCallback() {
    this.querySelector('button').onclick = () => {
      this.set('count', v => v + 1);
    };

    this.effect(() => {
      this.querySelector('.count').textContent = this.get('count');
    });
  }
});

What is UIElement?

UIElement is a "look ma, no JS framework!" library bringing signals-based reactivity to Web Components. It is one possible way to achieve these three goals:

Why UIElement?

JavaScript frameworks have solved these problems before and are more mature. – Why should you use UIElement?

  • Less size: Because you probably don't need everything these frameworks provide. For a small widget you might not want to add 10kB+ framework code that delays the initial page load. – UIElement is really small (around 100 lines of code; minified less than 1kB).
  • Less risk: Because you want to minimize risks of suddenly breaking things when you update node packages. – UIElement has zero (0) dependencies. If you want to understand the library, you have to read one single file before you decide whether its suitable and solid enough for your purposes.
  • More future: Because you want to build on technologies that won't be obsolete in 5 to 10 years. – HTML, CSS, JavaScript in general and Web Components specifically will outlive abstraction layers like JSX, Sass, TypeScript and any fancy JavaScript framework. UIElement adds a really thin layer on top of Web Components. – Come on, 100 lines of code! This much you could rewrite over a weekend as worst-case scenario. For example, when you think the maintainer of UIElement is going in the wrong direction or doesn't care enough for what you really need.

A Big But ...

The API of UIElement is not yet stable.

This is version 0.4.0. From version 0.1.0 to 0.2.0, I decided to overthow one part of the cause() and effect() interface that was inspired by my earlier attempts in a Codepen. Instead, "causes" for effects are now called "states", which I think is a more familiar terminology. And as I realized that the code needed to assert valid property names (to avoid clashes with JavaScript reserved words, global HTML attributes and method names) would be at least as much as the whole reactivity core, I decided to opt for a Map-like interface for states (internally a real Map is used). I cannot exclude the possibility that findings like these will emerge while I start to use the UIElement for more complex things and the code-base matures.

Alternatives

UIElement is not for you, if ...

  • You want isomorphic components, that is, the same component format on server and client side. We use split components in UIElement that are behavior-only JavaScript on the client side. This allows to use any rendering technology of your choice on the server side, because it's just regular HTML and CSS. It also enforces to write minimally invasive DOM updates. UIElement does not render components at all, thus completly bypassing potentially ineffient and error-prone DOM diffing. – You might try Enhance instead, if you insist on having isomorphic components able to render also on the client side.
  • You want more syntactic sugar for event handling, rendering, Shadow DOM, and TypeScript compilation. We deliberately don't do all of that in UIElement to keep the layer added on top of Web Components as thin as possible. Event handling is easy even in vanilla JavaScript. Rendering and Shadow DOM are avoidable. TypeScript adds the need for a compilation step we want to avoid. – You might try Lit instead, if you are not happy about our minimalism.
  • You want resumability, that is, the JavaScript application runs on the server side and loads client-side JavaScript only when needed. UIElement avoids the most expensive hydration step, rendering, so the performance gain achieved by resumability is small. Resumability is a candidate for future versions of UIElement though, but I haven't figured out how to do that best with Web Components. – You might try Qwik instead, but then you are back to React-ish JSX components in place of native Web Components.

How to Get Started?

If you understand the above remarks, you may install UIElement:

SHELL

npm install @efflore/ui-element

Read on ➔