Web Components — Cheat Sheet

Tags: web-components, custom-elements, shadow-dom, html-templates, frontend, javascript, standards

Level: intermediate

TL;DR: Standard browser suite (Custom Elements, Shadow DOM, HTML Templates) for framework-agnostic, encapsulated UI components. Consult for lifecycle methods, DOM isolation, and slot distribution mechanics.

Key concepts

Suite of three W3C standards: Custom Elements, Shadow DOM, and HTML Templates.

Custom Elements require hyphenated tag names to prevent collisions with future native HTML tags.

Shadow DOM provides CSS scoping and DOM encapsulation away from document queries.

Open Shadow DOM exposes element.shadowRoot; closed mode returns null.

<template> holds inert HTML markup parsed by the browser without executing scripts or styles.

<slot> elements act as placeholders in Shadow DOM for consumer-provided light DOM content.

connectedCallback fires when an element is inserted into the document DOM.

disconnectedCallback executes cleanup logic when the element is detached from DOM.

attributeChangedCallback triggers exclusively for attributes listed in observedAttributes.

adoptedCallback triggers when the component is moved to a new document context.

Typical questions and ready answers

Q: What is the primary difference between open and closed Shadow DOM?R: I always use open mode because closed only hides element.shadowRoot from external JavaScript without offering real security. Closed mode complicates testing, accessibility auditing, and external tooling while adding zero practical protection against deliberate inspection.

Q: How do Custom Element attributes differ from properties, and how do you keep them synchronized?R: Attributes live in the HTML markup as strings, whereas properties reside on the JS DOM object and support complex types. I sync them by using getters and setters on the class that map directly to getAttribute and setAttribute for primitive values, while reacting to changes via observedAttributes and attributeChangedCallback.

Q: Why use Web Components instead of framework-native components like React or Vue?R: Web Components are native browser standards, making them interoperable across any framework and ideal for cross-team design systems. I leverage them to build long-term, dependency-free UI primitives that outlive framework migration cycles.

Pitfalls and common mistakes

Accessing or rendering light DOM children inside the constructor() before connectedCallback runs.

Modifying DOM attributes inside constructor(), which violates the Custom Elements specification.

Expecting styles defined in external CSS to automatically style internals of an open Shadow DOM root.

Forgetting to declare attributes in static get observedAttributes() before expecting attributeChangedCallback to trigger.

Passing non-string primitives directly into attributes without proper stringification or using JS properties instead.

Breaking Form-Associated Custom Elements validation by omitting static formAssociated = true and ElementInternals.

Snippets and commandsTypeScript

// Custom Element definition with Shadow DOM and observed attributes
class UserCard extends HTMLElement {
  static observedAttributes = ['name', 'role'];
  private root: ShadowRoot;

  constructor() {
    super();
    this.root = this.attachShadow({ mode: 'open' });
  }

  connectedCallback(): void {
    this.render();
  }

  attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {
    if (oldValue !== newValue) {
      this.render();
    }
  }

  private render(): void {
    const name = this.getAttribute('name') ?? 'Guest';
    const role = this.getAttribute('role') ?? 'Viewer';
    this.root.innerHTML = `
      <style>
        :host { display: block; border: 1px solid #ccc; padding: 12px; }
        ::slotted(p) { color: #555; }
      </style>
      <div>
        <h3>${name}</h3>
        <span>${role}</span>
        <slot></slot>
      </div>
    `;
  }
}

customElements.define('user-card', UserCard);

To review

[ ] ElementInternals API for native form association and accessibility states

[ ] CSS :host, :host-context(), and ::slotted() selector precedence

[ ] Constructable Stylesheets via CSSStyleSheet() and adoptedStyleSheets

[ ] Declarative Shadow DOM using <template shadowrootmode="open">

[x] Custom element lifecycle callbacks ordering

References

MDN Web Docs: Web Components API Reference

WHATWG HTML Standard: Custom Elements Specification

W3C DOM Standard: Shadow DOM Specification

Jarvis Interviews
Jarvis