A plataforma web vem evoluindo a todo vapor já faz algum tempo, muitas tecnologias vão atingindo uma maturidade bacana e começam a ser adotadas por mais e mais pessoas.

Hoje vamos falar sobre Web components e mergulhar mais fundo no que a web tem para nos oferecer.

O que são os Web Components?

Web components são três tecnologias separadas que são usadas em conjunto e permitem a criação de elementos customizados reutilizáveis.

As três tecnologias são:

  1. Custom Elements
  2. Shadow DOM
  3. HTML Templates

Custom elements

Um dos principais recursos dos Web components é a capacidade de criarmos elementos personalizados onde nossa funcionalidade fica encapsulada.

Como o nome já entrega, custom elements são elementos HTML, como <div>, <section> ou <article>, porém são elementos que podemos nomear e que são definidos por meio de uma API do navegador, ou seja, uma Web API.

Os custom elements contêm suas próprias semânticas, comportamentos e marcações e podem ser compartilhados entre estruturas e navegadores.

class MeuComponente extends HTMLElement {
  connectedCallback() {
    this.innerHTML = `<h1>Olá Mundo!</h1>`;
  }
}

customElements.define('meu-componente', MeuComponente);

No exemplo acima, definimos <meu-componente> e seu próprio elemento HTML. Não parece muito útil por enquanto, pois é só uma tag que renderiza um texto qualquer, mas vamos evoluir a ideia logo mais. Todos os custom elements devem estender HTMLElement de alguma maneira para que possam ser registrados no navegador.

Os custom elements existem sem o uso de frameworks, e os navegadores se dedicam a retrocompatibilidade da específicação, o que quase garante que os componentes que foram criados com base na especificação não sofreram de breaking API changes.

Outra coisa bacana é que esses componentes geralmente estão prontos para uso com praticamente todos as libs e frameworks mais populares atualmente, como Angular, React e Vue.

Shadow DOM

O Shadow DOM é uma versão encapsulada do DOM. Isso permite que fragmentos do DOM sejam isolados uns dos outros, incluindo qualquer coisa que possa ser usada como um seletor CSS. Com o Shadow DOM, você é capaz de isolar o CSS e JavaScript do seu web component.

Geralmente, qualquer conteúdo dentro do document é referenciado como light DOM, e qualquer conteúdo encapsulado é referenciado como shadow DOM.

Normalmente, estamos usando o light DOM e podemos selecionar um elemento simplesmente fazendo document.querySelector('.meu-seletor').

Já a shadow DOM funciona semelhante a um iframe, onde o conteúdo é separado do resto do document. No entanto, quando criamos um shadow DOM, ainda temos controle total sobre esse fragmento da nossa página, mas com escopo específico. Isso é o que chamamos de encapsulamento.

Vamos a um exemplo:

HTML

<section>
    <div id="exemplo">Meu botão com cor vermelha</div>
    <button id="botao">Meu botão que não vai ter a cor vermelha</button>
</section>

Javascript

const shadowRoot = document.getElementById('example').attachShadow({ mode: 'open' });
shadowRoot.innerHTML = `<style>
    button {
      background: tomato;
      color: white;
    }
</style>
<button id="button"><slot></slot> tomato</button>`;

O shadow root pode incluir conteúdo do seu document, usando o elemento <slot>. Usar um slot removerá o conteúdo do document externo e o colocará em um local determinado pela tag <slot> dentro do shadow root.

O resultado no navegador seria esse:

<section>
  <div id="exemplo">
    <!-- Pseudo-código usado para designar um shadow root -->
    <#shadow-root>
      <style>
      button {
        background: red;
        color: white;
      }
      </style>
      <button id="botao">Meu botão com cor vermelha</button>
    </#shadow-root>
  </div>
  <button id="botao">Meu botão que não vai ter a cor vermelha</button>
</section>

HTML Templates

São modelos definidos pelo usuário em HTML que não são renderizados até que sejam solicitados.

Quando precisamos reutilizar uma estrutura HTML, faz sentido ter um template para evitarmos de escrever várias vezes o mesmo código. Isso já era possível fazer antes, porém agora com o HTML template, ficou muito mais fácil.

Este elemento e seu conteúdo não são renderizados no DOM, mas ainda podem ser referenciados usando JavaScript.

Exemplo:

<template id="users-template">
  <li><span class="name"></span> &mdash; <span class="lastname"></span></li>
</template>

<ul id="users"></ul>

O exemplo acima não vai renderizar nenhum conteúdo até que um javascript consuma o modelo, instancie o código e diga ao navegador o que fazer com ele.

Vamos fazer isso agora:

const fragment = document.getElementById('users-template');
const users = [
  { name: 'Albert', lastname: 'Einstein' },
  { name: 'Nikola', lastname: 'Tesla' },
  { name: 'Galileu', lastname: 'Galilei' },
];

users.forEach(user => {
  // Cria uma instancia do template
  const instance = document.importNode(fragment.content, true);
  // Adiciona o conteúdo ao template
  instance.querySelector('.name').innerHTML = user.name;
  instance.querySelector('.lastname').innerHTML = user.lastname;
  // Adiciona a instancia no DOM
  document.getElementById('users').appendChild(instance);
});

Observe que neste exemplo criamos um modelo <template id = "users-template"> sem qualquer outra tecnologia de Web Components, ilustrando novamente que as três tecnologias podem ser usadas de forma independente ou coletiva.

Conclusão

Os Web Components estão aí para ficar, e se você ainda não conhecia ou não havia testado e brincado com eles, eu sugiro colocar isso na sua lista de tecnologias a testar agora mesmo.

As especificações dos Web Components são um conjunto de APIs de baixo nível que continuarão a crescer e evoluir conforme nossas necessidades como desenvolvedores evoluírem.

Em um post futuro, vamos falar sobre uma ferramenta bem bacana que pode nos ajudar a criar web components reutilizáveis, nossa própria biblioteca de componentes, ou até mesmo um Design System escalável.

Alguns links que vão te ajudar a se aprofundar no assunto:

Até mais e obrigado pelos peixes.