Web Components Guide


What are Web Components?

Web Components are a native way for web developers to build user interfaces. They're built right into your browser so you don't have to download any framework to get started. Web Components fit right into your existing HTML today. If you've got a server that can render HTML, then you can render Web Components.

Web Components allow you to extend the vocabulary of your HTML. You can define new behaviors that go beyond the built in tags. New features such as <slide-out-menu> or <stop-watch> are at your finger tips. JavaScript can drive these definitions, allowing advanced behaviors and interactions.

Custom Element tag names are required to include a dash (-) in their name. Having a dash makes them easier to tell apart from native (built-in) elements. New built-ins will never have a dash, and so won't conflict.

Here's an example of a web component that renders a timer. It defines its own styles, it renders into a ShadowDOM, and has its own private state. It makes use of the lifecycle callbacks to know when to start counting. These are all built in web platform features.

// Create a new stylesheet that can be shared by all `stop-watch` elements
const styles = new CSSStyleSheet()
  :host {
    font-size: var(--font-size-3);
    font-style: italic;

// Define the StopWatch element Class
class StopWatchElement extends HTMLElement {
  static define(tag = "stop-watch") {
    customElements.define(tag, this)

  // Give this element its own encapsulated DOM
  shadowRoot = this.attachShadow({ mode: "open" })

  // Initialize private state
  #start = Date.now()

  connectedCallback() {
    // Add the shared styles
    this.shadowRoot.adoptedStyleSheets = [styles]

    // Start the timer

  #tick() {
    const milliseconds = Date.now() - this.#start
    const minutes = String(Math.floor(milliseconds / (1000 * 60))).padStart(2, "0")
    const seconds = String(Math.floor((milliseconds / 1000) % 60)).padStart(2, "0")
    const hundredths = String(Math.floor((milliseconds % 1000) / 10)).padStart(2, "0")


    // Schedule next update
    requestAnimationFrame(() => this.#tick())

// Register the element with the Custom Element Registry
<stop-watch role="timer"></stop-watch>

Let's find out more about how to build this component...