# Web Components flashcards

# Introduction

What's the purpose of Web Components ?

  • create reusable components
  • w/ vanilla JS/HTML/CSS only!
  • without fear of code collisions

What are the 3 main technologies behind Web Components?

  • Custom elements
  • Shadow DOM
  • HTML Templates

What are the usual steps required to define a Web Component?

  1. Create a class or a function in which you specify your web component functionality
  2. register your custom element
  3. (optional) attach a shadow DOM to the custom element
  4. (optional) define an HTML template using <template> and <slot>, clone the template and attach it to your shadow DOM.

You can now use your custom element wherever you like on your page, just like you would any regular HTML element.

What method permits to register a custom element?

CustomElementRegistry.define()

Passing it:

  1. the element name to be defined
  2. the class or function in which its functionality is specified
  3. (optionally) what element it inherits from

What method permits to attach a shadow DOM to a custom element?

Element.attachShadow()


references

# Custom Elements

For what purposes do we use Custom Elements?

  • create new HTML tags
  • beef-up existing HTML tags
  • or extend the components other developers have authored

What should you avoid when you're looking for information about the Custom Element standard?

To confuse it with the "v0 version", a working draft which have only been implemented by Chrome & Opera.

The actual (or v1) Custom Element standard is the one defined in the WHATWG html living standard, and now supported by most browsers.

What global object permits to manage Custom Elements registration?

Window.customElements

How using a Custom Element is different from using any other HTML element?

It's NOT!

A Custom Element constructor needs to extend the HTMLElement interface in order to inherit the entire DOM API!

Define a <dumb-element> Custom Element.

class DumbElement extends HTMLElement {...}
window.customElements.define('dumb-element', DumbElement);

// Or use an anonymous class if you don't want a named constructor in current scope.
window.customElements.define('dumb-element', class extends HTMLElement {...});

What do you define using a CE class?

The CE public JavaScript API and some of its behavior.

For example, you could define how to "open" an <app-drawer> CE like so:

class AppDrawer extends HTMLElement {

  // A getter/setter for an open property.
  get open() {
    return this.hasAttribute('open');
  }

  set open(val) {
    // Reflect the value of the open property as an HTML attribute.
    if (val) {
      this.setAttribute('open', '');
    } else {
      this.removeAttribute('open');
    }
    this.toggleDrawer();
  }

    // Can define constructor arguments if you wish.
  constructor() {
    super();

    // Setup a click listener on <app-drawer> itself.
    this.addEventListener('click', e => {
      this.toggleDrawer();
    });
  }

  toggleDrawer() {
    ...
  }
}

What should you always do if you define a constructor for a CE class?

If you define a constructor, always call super() first! This is specific to CE and required by the spec.

What are the 3 rules your have to follow when defining a CE?

  1. The name of a custom element must contain a dash (-).

So <x-tags>, <my-element>, and <my-awesome-app> are all valid names, while <tabs> and <foo_bar> are not. This requirement is so the HTML parser can distinguish custom elements from regular elements. It also ensures forward compatibility when new tags are added to HTML.

  1. You can't register the same tag more than once.

Attempting to do so will throw a DOMException.

  1. Custom elements cannot be self-closing.

This is because HTML only allows a few elements to be self-closing. Always write a closing tag ().


references

# Templates & Slots

What are the attributes and elements permitting to use slots?

Inside a template or your WC, use the <slot> element in order to define a placeholder:

customElements.define(
  'my-element',
  class extends HTMLElement {
    constructor() {
      super();

      const shadow = this.attachShadow({ mode: 'open' });
      const container = document.createElement('div');

      container.innerHTML = `
        <slot name="title"></slot>
      `;

      shadow.appendChild(container);
    }
  }
);

Use the slot attribute to define the content for this slot:

<my-element>
  <span slot="title">Hello World!</span>
</my-element>

You can also use one anonymous slot by removing the name attribute and the slot attribute value.

# Styling

How could you selectively expose chosen elements from their shadow tree to the outside page for styling purposes?

You can use CSS Shadow Parts for that!

The experimental ::part CSS pseudo-element permits to select an element within a shadow tree that has a matching part attribute.

Here is an example:

light tree

<style>
  custom-element::part(hello-world) {
    color: red;
  }
</style>
<custom-element></custom-element>

shadow tree (in your WC)

<div part="hello-world">
  Hello World!
</div>

⚠️ highly experimental

This feature is only at the first stage for W3C specification ("First Public Working Draft"). It's only supported by Chrome 73 and Firefox 69 behind the layout.css.shadow-parts.enabled preference. Check the explainer, Editor's Draft and issues before using it in production, and be prepared for changes!

# Acknowledgments

Portions of this flashcards are modifications based on:

Copyright © 2019 Noël Macé (noelmace.com). This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License .