BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News Github Releases Catalyst to Ease the Development of Web Components in Complex Applications

Github Releases Catalyst to Ease the Development of Web Components in Complex Applications

This item in japanese

Bookmarks

GitHub recently released the first major iteration of Catalyst, a set of patterns and techniques for developing with web components in complex applications. Catalyst strives to be small and is used for the GitHub website that is entirely written in vanilla JavaScript and web components.

The GitHub Catalyst documentation explains:

Catalyst is a set of patterns and techniques for developing components within a complex application. At its core, Catalyst simply provides a small library of functions to make developing Web Components easier. The library is an implementation detail, though. The concepts are what we’re most interested in.

In the early days of jQuery, web applications would be written without the indirection proposed by frameworks. Developers would put event handlers on interactive DOM elements (direct event binding) or anchoring ancestor elements (event delegation). Those handlers would do some work and possibly update the DOM. That meant querying the DOM to find the elements to update. In a talk at the Web Component SF Meetup earlier this year, Kristján Oddsson, core contributor of Catalyst, illustrated how a simple behavior would be implemented in vanilla JavaScript at GitHub:

// Direct event binding
on('click', 'js-hello-world-button', function (event) {
  const button = event.currentTarget;
  // DOM Querying
  const container = button.closest('js-hello-world');
 
  const input = container.querySelector('js-hello-world-input');
  const output = container.querySelector('js-hello-world-output');

  output.textContent = `Hello, ${input.value}`
}

with the corresponding HTML on the page:

<div class="js-hello-world">
  <input class="js-hello-world-input" type="text">
  <button class="js-hello-world-button">
    Greet
  </button>
  
  <span class="js-hello-world-output"></span>
</div>

While the previous vanilla JavaScript approach is simple and abstraction-free, it nonetheless has drawbacks when used at scale. Oddsson mentioned a few in his talk: a naming scheme is required, the DOM querying is explicit, classes are not scoped and could be overloaded unwillingly.

Catalyst leverages custom elements, one of the four legs of the web component standard, to solve some of the issues linked to a pure vanilla approach. Catalyst strives to be minimal, leverages web standards, and favors progressive enhancement. The documentation explains:

From [our experimentation] emerged a set of patterns which were reduced down to their first principles. Observing elements on the page, listening to the events these elements or their children emit, and querying the children of an element to mutate or extend them.

Custom elements are annotated with a set of data-* attributes that cover the listening and querying concerns. The DOM MutationObserver API is then used to automatically bind behavior to the custom elements when they appear (or disappear) on the page.

The data-target attribute allows binding to a specific property of a custom element according to a naming scheme (convention-over-configuration approach). The data-action attribute allows binding methods upon instantiation of a custom element. The documentation provides the following example:

<hello-world>
  <input
    data-target="hello-world.name"
    type="text"
  >

  <button
    data-action="click:hello-world#greet">
    Greet
  </button>

  <span
    data-target="hello-world.output">
  </span>
</hello-world>

import { controller, target } from "@github/catalyst"

@controller
class HelloWorldElement extends HTMLElement {
  @target nameTarget: HTMLElement
  @target outputTarget: HTMLElement

  greet() {
    this.outputTarget.textContent =
      `Hello, ${this.nameTarget.value}!`
  }
}

Here, hello-world.output relates to the outputTarget property of a HelloWorld custom element, implemented by the class HelloWorldElement. The data-action="click:hello-world#greet" visible on the button in the previous HTML code specifies that an onclick event handler has to be bound to the button. It additionally specifies that the event handler is the greet method of the HelloWorld custom element.

Catalyst leverages TypeScript decorators for a better developer experience. The use of decorators is however optional. Custom elements extend native HTML elements and enable progressive enhancement.

Catalyst is used in the implementation of GitHub’s website with custom elements. GitHub open-sourced 17 custom elements that are used on its website.

Catalyst is open source software distributed under an MIT license. Feedback and contributions are welcome and should follow the project’s code of conduct and contributing guidelines.

Rate this Article

Adoption
Style

BT