Introduction to Web Components and PatternFly Elements

Benny Powers Principal UX Engineer

Portions © WHATWG (CC-BY), MDN (CC-BY-SA)

Introduction to Web Components

In this Presentation

  1. DOM as the basis for frontend work
  2. Custom Elements - HTML with an API
  3. Shadow DOM for encapsulation
  4. New Concepts in CSS
  5. Accessibility Concerns
  6. Libraries and Ecosystem

Web Components at Red Hat

  1. PatternFly Elements
  2. Red Hat Design System

Introduction to Web Components

Document Object Model

Anything found in an HTML document can be accessed, changed, deleted, or added using the Document Object Model

W3C

screenshot of elements inspector from firefox dev tools

Document Object Model

The DOM: Document Object Model

As the browser downloads an HTML page, it instantiates a DOM for the document.

  • Every HTML element becomes an element node
  • The <html> element becomes the root document node
  • HTML Text content becomes text nodes
  • Comments become comment nodes

This happens while the server streams HTML to the client, but <script> elements and other subresources can halt streaming DOM construction and impair page performance.

Document Object Model

Manipulating the Document

  • querySelector(selector)
  • node.append()
    node.remove()
  • document.createElement(tagName)
  • element.setAttribute(name, value) element.removeAttribute(name) element.toggleAttribute(name)

Document Object Model

Attributes and Properties

  • HTML Attributes: key-value pairs on elements in a Document

    • Add data and behaviour to elements
    • Part of the Document - Always strings
    • correspond with the attributes DOM property and *Attribute() methods
  • DOM Properties: JavaScript object properties on a DOM node

    • JavaScript Objects like any other
    • Mutating properties / calling methods can update the Document
  • Frontend Frameworks often 'abstract' away the difference between attributes and properties

Document Object Model

Attributes and Properties

Some attributes are paired with corresponding DOM properties

  • element.id reflects to the id attribute
  • element.setAttribute('id') sets the id property
  • input.value does not reflect to the value attribute
  • input.setAttribute('value') does not set the value property

Document Object Model

Events

Node inherits from EventTarget

  • click / tap / scroll / mouseenter / mouseleave
  • keyup / keydown
  • focus / blur
  • dragstart / dragstop / drop

Events have target and path properties which provide rich detail about the state of the DOM.

Document Object Model

Event Listeners

document.querySelector('canvas')
  .addEventListener('mousemove', function(event) {
    const ctx = this.getContext('2d');
    ctx.fillStyle = 'black';
    ctx.fillRect(event.clientX, event.clientY, 2, 2);
  });

Introduction to Web Technologies

What are Web Components?

Because web components are native to the web, they can travel to any web-based environment.

Brad Frost

gears in a machine

What are Web Components?

Custom Elements

In the DOM, each element relates to a specific class. Custom Elements are HTML tags containing a hyphen which are associated with a user-defined JavaScript class through the customElements namespace.

class FancyElement extends HTMLElement {
  fanciness = 11;
}

customElements.define('fancy-element', FancyElement);

Custom Elements are HTML elements with user-defined DOM APIs.

What are Web Components?

The <template> Element

Parse HTML into the DOM once, clone it cheaply many times.

<template id="fancy-template">
  <article>
    <h2>Name</h2>
    <p class="description"></p>
    <footer><a>Read More</a></footer>
  </article>
</template>
document.getElementById('fancy-template')
  .content
  .cloneNode(true);

What are Web Components?

Shadow DOM

A private, encapsulated DOM subtree, attached to an element.

firefox element inspector highlighting an open shadow root

  • DOM isolation (unique IDs)
  • Style Encapsulation (simple selectors)
  • Event Retargeting

What are Web Components?

Declarative Shadow DOM

<host-element>
  <template shadowrootmode="open">
    <style>shadow styles</style>
    <h2>Shadow Content</h2>
    <slot></slot>
  </template>
  <h2>Light content</h2>
</host-element>

github.com/mfreed7/declarative-shadow-dom

What are Web Components?

The <slot> Element

Projects contents from the "light" DOM into positions in the Shadow Root.

firefox element inspector showing a slotted element
::slotted(h2) {
  color: var(--rh-color-brand-red-on-light);
}

What are Web Components?

Styling Web Components

CSS Custom Properties

  • Inherit ∴ pierce shadow boundaries
  • Useful for theming, animation, conditional CSS

CSS Shadow Parts

  • Expose shadow elements as stylable
  • Makes author-selected private elements public

What are Web Components?

CSS Custom Properties

Shadow CSS:

#content {
  background: var(--content-background, transparent);
}

Light CSS:

x-element {
  --content-background: red;
}

What are Web Components?

CSS Shadow Parts

Shadow DOM:

<div id="content" part="content">
  <slot></slot>
</slot>

Light CSS:

x-element::part(content) {
  background: red;
  padding: 2em;
}

Accessibility

Accessibility

Form-Associated Custom Elements

<label>Label Association
  <x-checkbox checked></x-checkbox></label>

ElementInternals

class FancyElement extends HTMLElement {
  #internals = this.attachInternals();
  set value(v) {
    this.#internals.ariaValueNow = v.toString();
  }
}

Accessibility

Cross-Root ARIA

<span id="foo">Description!</span>

<x-foo aria-label="Hello!" aria-describedby="foo">
  <template shadowroot="closed"
            shadowrootdelegatesariaattributes="aria-label aria-describedby">
    <input id="input" delegatedariaattributes="aria-label aria-describedby">
    <span             delegatedariaattributes="aria-label">Another target</span>
  </template>
</x-foo>

github.com/leobalter/cross-root-aria-delegation

Libraries and Ecosystem

Libraries and Ecosystem

Lit

The 'original' web components library

  • Adds declarative rendering and reactivity on top of HTMLElement
  • Works well with (but does not require) TypeScript
  • Performant updates - no VDOM overhead
  • Just JavaScript - no babel, no JSX
@customElement('lit-thingy') class LitThingy extends LitElement {
  @property() type: 'saucy'|'sassy';
  render() {
    return html`
      <span>feeling ${this.type}</span>
    `;
  }
}

Libraries and Ecosystem

FAST

Microsoft's Web Component framework and Design System

  • Declarative functional templates combined with class components
  • Innovative data binding system with Observables
  • Comes with it's own design system
const template = html<FASTThingy>`
  <span>feeling ${x => x.type}</span>
`;
@customElement({
  name: 'fast-thingy',
  template
})
class FASTThingy extends FASTElement {
  @attr() type: 'saucy'|'sassy';
}

Libraries and Ecosystem

Haunted

React-like hooks, but it's web components

import { html } from 'lit';
import { component, useState } from 'haunted';

function Counter() {
  const [count, setCount] = useState(0);

  return html`
    <div part="count">${count}</div>
    <button part="button" @click=${() => setCount(count + 1)}>
      Increment
    </button>
  `;
}

customElements.define('my-counter', component(Counter));

What are Web Components?

The Future of Web Components

  • CSS / HTML Modules
  • Declarative Custom Elements
  • DOM Parts / Template Instantiation
  • Open Stylable Shadow Roots
  • Scoped Custom Element Registries

Web Components at Red Hat

PatternFly Elements

patternfly elements v1 logopatternfly logo

Web Components at Red Hat

Please join me in the Digital Experience Source Deck (Red Hat Internal)

Introduction to Web Components and PatternFly Elements