Introduction to Web Components and PatternFly Elements
Portions © WHATWG (CC-BY), MDN (CC-BY-SA)
Introduction to Web Components
In this Presentation
- DOM as the basis for frontend work
- Custom Elements - HTML with an API
- Shadow DOM for encapsulation
- New Concepts in CSS
- Accessibility Concerns
- Libraries and Ecosystem
Web Components at Red Hat
- PatternFly Elements
- Red Hat Design System
Introduction to Web Components
Document Object Model
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 theid
attributeelement.setAttribute('id')
sets theid
propertyinput.value
does not reflect to the value attributeinput.setAttribute('value')
does not set the value property
Document Object Model
Events
- 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?
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.
- 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>
What are Web Components?
The <slot>
Element
Projects contents from the "light" DOM into positions in the Shadow Root.
::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>
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
Web Components at Red Hat
Please join me in the Digital Experience Source Deck (Red Hat Internal)