Introdução aos Web Components

Introdução aos Web Components

Entenda quais são as tecnologias envolvidas na criação de Web Components

Este é o primeiro artigo de uma série onde iremos entender os conceitos básicos sobre Web Components e como utilizá-los em qualquer projeto (independente do framework) 🙂

Os web components permitem a criação de elementos HTML customizados, reutilizáveis e com suas funcionalidades encapsuladas. Para isso são utilizadas, basicamente, três tecnologias:

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

O conjunto dessas tecnologias é que permite a criação dos Web Components, no entanto, cada uma delas pode ser utilizada de forma isolada. A seguir, vamos entender o funcionamento de cada uma e como utilizá-las na criação dos nossos componentes.

Custom Elements

Utilizando os Custom Elements podemos criar elementos HTML personalizados mantendo toda sua lógica "encapsulada". Simples, certo?

gatinho_carregando.png

Por exemplo, imagine que precisamos construir uma lista ordenada onde cada item contém um link que nos encaminha para uma página da MDN.

Conhecendo HTML essa é uma tarefa fácil, mas se fosse necessário utilizar essa lista em muitos lugares provavelmente você terminaria com muito código repetido. Nesse caso, podemos criar um elemento customizado e reutilizá-lo em todos os lugares necessários. Vamos criar um elemento desses para nossa lista?

  • Primeiramente definimos no nosso JS uma classe responsável por implementar o comportamento do nosso componente e estendemos HTMLElement.
  • No construtor da classe chamamos o método super() para realizar a construção da cadeia de Prototypes.
  • Por fim, utilizamos a API de Custom Elements e registramos nosso elemento, passando como primeiro argumento o nome do nosso elemento (web-components-list) e como segundo argumento seu comportamento dado por nossa classe (WebComponentsList).

Lembre-se que o nome dos seus componentes deve sempre conter um traço (kebab-case) não podendo ser constituído apenas de palavras isoladas.

class WebComponentsList extends HTMLElement {
  constructor () {
    super();
  }
}

customElements.define('web-components-list', WebComponentsList);

Mas nossa classe não tem nenhum comportamento além de chamar o método super()!

Exatamente, cuidaremos disso agora. Vamos adicionar o HTML necessário para a nossa funcionalidade e atribuí-lo ao innerHTML do nosso objeto.

class WebComponentsList extends HTMLElement {
  constructor () {
    super();
    this.innerHTML = `
      <ol>
        <li><a href="https://developer.mozilla.org/pt-BR/docs/Web/Web_Components/Using_custom_elements" target="_blank">Custom Elements</a></li>
        <li><a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM" target="_blank">Shadow DOM</a></li>
        <li><a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_templates_and_slots" target="_blank">HTML Templates</a></li>
      </ol>  
    `;
  }
}

customElements.define('web-components-list', WebComponentsList);

Agora no nosso HTML podemos simplesmente utilizar nosso componente como se fosse uma tag HTML comum. É possível ver o resultado logo abaixo:

(codepen.io/renanmac/pen/RwgaJPv)

Esse foi um caso simples de uso dos Custom Elements, no entanto, eles podem ser muito mais poderosos do que isto. Além de serem divididos entre Autônomos e Integrados possuem callbacks de ciclo de vida que permitem construir funcionalidades ainda mais complexas. Caso queria entender esses pontos com mais detalhes recomendo essa página (Usando custom elements).

Shadow DOM

Os Custom Elements que comentamos anteriormente permitem a criação de elementos personalizados e com seu comportamento encapsulado, certo? Errado (Mais ou menos na realidade).

A verdade é que mesmo estando "encapsulado" é possível que existam "vazamentos" tanto de dentro do elemento para fora como do elemento para dentro. É aí que entra o Shadow DOM.

Ele fornece uma forma de anexarmos, algo como, um "novo" DOM ao DOM Principal. Dessa forma, conseguimos garantir que esses "vazamentos" não ocorram. (Ainda não sabe o é DOM?)

bebe_yes.png

Vamos retomar o exemplo anterior e criar um Shadow DOM para o nosso elemento 🙂.

  • Utilizaremos o método attachShadow para criar um Shadow DOM onde adicionaremos nosso componente. O método attachShadow recebe como argumento um objeto de opções, no caso, temos apenas a opção mode onde seu valor pode ser open ou close. Utilizar a opção open significa que seu Shadow DOM será acessível via JS fora do contexto do seu componente, já com a opção close seu Shadow DOM não poderá ser acessado por JS fora do contexto do componente.
  • Com a chamada do attachShadow criamos nosso Shadow DOM e agora temos acesso ao nó principal desse "novo" DOM a partir da propriedade shadowRoot.
  • Por fim, adicionaremos nossa lista a propriedade innerHTML do nosso shadowRoot e seguiremos com a definição do nosso elemento.
class WebComponentsList extends HTMLElement {
  constructor () {
    super();
    this.attachShadow({ mode: 'open'});
    this.shadowRoot.innerHTML = `
      <ol>
        <li><a href="https://developer.mozilla.org/pt-BR/docs/Web/Web_Components/Using_custom_elements" target="_blank">Custom Elements</a></li>
        <li><a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM" target="_blank">Shadow DOM</a></li>
        <li><a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_templates_and_slots" target="_blank">HTML Templates</a></li>
      </ol>    
    `;
  }
}

customElements.define('web-components-list', WebComponentsList);

Podemos ver o resultado logo abaixo 🙂.

Note que o CSS definido fora do nosso componente não exerce nenhum impacto sobre ele, assim como qualquer estilo definido dentro do nosso componente não afetará nenhum elemento de fora. Irado, né?

(codepen.io/renanmac/pen/ExXKrmE)

Deixo aqui a documentação da MDN onde você pode conferir outros exemplos, uma explicação de como o Shadow DOM é anexado ao DOM Regular assim como todas as possibilidades de uso.

HTML Templates

Algo comum de ocorrer no desenvolvimento de aplicações web é ter certas porções de HTML que são muito parecidas entre si. Certo? E se eu dissesse que é possível extrair essas porções e criar templates que podem ser utilizados por toda sua aplicação. Qual seria sua reação?

leonidas_fala_agora.png

Nossa principal aliada será a tag <template> . Com ela podemos definir nosso HTML, assim como os estilos e os scripts, e nada disso será renderizado pelo navegador até que tomemos a decisão de exibi-los.

Retomando nosso exemplo da lista, poderíamos criá-la utilizando um HTML Template. O JS responsável pela criação faria o seguinte:

  • Buscaria o template através do querySelector (ou qualquer outra forma de buscar elementos no DOM)
  • Criaria um cópia do conteúdo do nosso template através do método importNode e o adicionaria ao body.
const template = document.querySelector('#web-components-list');
document.body.appendChild(document.importNode(template.content, true));

Simples, né? Confere aqui 👇

(codepen.io/renanmac/pen/zYzByvO)

Ainda podemos adicionar mais flexibilidade aos nossos templates HTML com o uso dos slots. Mas não vou me estender muito nesse assunto hoje, mas vou deixar o link da documentação, caso queira saber tudo sobre slots.

Juntando as peças 🧩

Essas três tecnologias combinadas são a base para a criação de Web Components. Pensa comigo, agora conseguimos criar um template com nosso HTML, estilos e scripts e deixar tudo organizado em um bloquinho. Podemos adicionar um Shadow DOM e garantir que nada disso vai vazar e impactar outras partes da nossa aplicação, e, para completar, ainda podemos definir um elemento com uma nome bem sugestivo bacanudo que vai englobar tudo isso.

Agora ficou fácil de entender, não ficou?

futurama_agora_eu_entendi

E agora? 🤔

Falta só criarmos um Web Component para chamar de nosso (❤️), certo? Certo.

Mas, para não me alongar demais, vou deixar esse assunto para o próximo post. Enquanto ele não sai porque você não aproveita para comentar o que achou desse post? Você utiliza Web Components? Já utilizou?

E, se você tiver alguma sugestão de algo que gostaria de ver implementado com Web Components, me conta também 😉.

Forte abraço, até a próxima.

Referências

  1. https://developer.mozilla.org/pt-BR/docs/Web/Web_Components
  2. https://css-tricks.com/an-introduction-to-web-components/