DEV Community

Valdeir S.
Valdeir S.

Posted on • Edited on

3

Web Components: Crie elementos personalizados com JavaScript

O que são (conceito)

Web Components são um conjunto de especificações elaboradas para permitir a criação de elementos web de forma customizada e independente.

Sites construídos com esse conceito tornam-se mais fáceis de manter, isto porque a alteração realizada num elemento será replicada em todo o site, facilitando as alterações e aumentando a produtividade.

A ideia não tão recente, surgiu por volta de 2011 numa conferência de Alex Russell, realizada na Fronteers Conference. Em 2012, começou a ganhar força com sua especificação de uso publicada no W3.

Apesar das diferenças, a chegada de novas bibliotecas — como a ReactJs e posteriormente a VueJs — ajudou a popularizar essa nova forma de programar, que visa separar e encapsular o site em pequenas estruturas.

As bibliotecas supramencionadas possuem técnicas e funcionamento diferentes se comparadas ao Web Componentes.

Atualmente, o conjunto de especificações é dividido em 3 peças (ou elementos).


Peças/Elementos

Peça 1) Shadow DOM

O DOM, na programação/marcação web, é uma API que nos permite acessar ou manipular documentos HTML (e XML). Cada um desses documentos é criado por uma árvore de nós com subnós.

Documento HTML

<!DOCTYPE html>
<html>
    <head>
        <title>Olá</title>
    </head>
    <body>
        <span style="color: red">Olá</span>
        <span>Mundo</span>
    </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Árvore de nós do documento supra

Árvore de nós do documento

O ShadowDOM é semelhante ao DOM, a principal diferença está na capacidade que ele tem em definir o encapsulamento de uma árvore DOM, a fim de isolá-la do documento principal. Nos navegadores modernos, podemos ver essa técnica em vários elementos HTML.

O código <input type="date" />, por exemplo, gerará uma árvore encapsulada, que  — apesar de um CSS próprio  —  o código não interfere no restante do documento principal e também não é interferido.

Estrutura escondida do elemento input date

Peça 2) Custom Elements

Como o próprio nome diz, esta peça fornece aos desenvolvedores uma maneira de criar elementos HTML personalizados, incluindo visualmente e com eventos específicos.
Adotado pelo Chromium em 2014 em modo experimental, a versão 0 (V0)  — que foi descontinuada em 2016  —  não foi implementada por outros navegadores, que passaram a utilizar as especificações da V1.

Exemplificação

Exemplo utilizando o componente emoji-picker

Peça 3) Template

Esta é usada como um fragmento de documento (DocumentFragment). Apesar de ele ser adicionado no documento HTML, o navegador ignora-o durante a renderização. Via JavaScript, é possível clonar e/ou modificá-lo antes de o inserir na árvore DOM.

Slots

Elementos slot são usados dentro do elemento template para indicar onde determinado(s) conteúdo(s) será(ão) renderizado(s).

Vantagens e Desvantagem

Vantagens

  • Reutilização: Podemos utilizar o mesmo elemento em diversos lugares do projeto, de forma simples.
  • Produtividade: A alteração do visual, forma ou adição de novos elemento é facilitada.
  • Encapsulamento: Com um elemento encapsulado, é possível trabalhar com mais liberdade e evitando conflitos entre códigos.
  • Nomenclatura eficiente: O encapsulamento permite que os atributos como class e id possam ser objetivos.

Desvantagens

  • Compatibilidade: É possível usar algumas bibliotecas para tornar os elementos compatíveis com navegadores antigos, mas a falta de suporte nativo é uma desvantagem.
  • Semântica: Navegadores e buscadores não entendem o significado do elemento <emoji-picker />. Isso pode ser contornado para os buscadores e leitores de tela.
  • Acessibilidade: Os elementos nativos possuem uma série de atributos que são utilizados pelos leitores de tela; nos customizados, a sua atenção deverá ser redobrada. É possível melhorar e adaptar essa questão.
  • JavaScript: É necessário que o JavaScript esteja habilitado para o componente funcionar. Navegadores com o recurso desabilitado ou de linha de comando (Lynx, por exemplo) poderão não funcionar corretamente (mas nem o Xavier Vídeos funciona).

Criando o primeiro componente

No primeiro exemplo, será criado um componente bem simples, cujo objetivo é dar boas vindas ao usuário.

Base

export default class Welcome extends HTMLElement {
constructor() {
super()
this._root = this.attachShadow({ mode: 'closed' })
}
attributeChangedCallback(attr, oldValue, newValue) {
this.connectedCallback()
}
connectedCallback() {
let name = 'Mundo'
if (this.hasAttribute('name')) {
name = this.getAttribute('name')
}
this._root.innerHTML = `<h1>Olá, ${name}!</h1>`
}
disconnectedCallback() {
this._root.innerHTML = '' // Limpa o elemento
}
static get observedAttributes() {
return ['name']
}
}
window.customElements.define('v-welcome', Welcome)
view raw welcome-01.js hosted with ❤ by GitHub

Na linha 1, foi definido uma classe que estende os atributos e métodos da classe HTMLElement. Todo componente deve ser filho da HTMLElement, caso contrário o navegador não conseguirá executar e invocar os métodos necessários.

Na linha 2 e 3; foi, respectivamente, definida a função construtora e a invocação da função constructor da classe pai, que é obrigatória. A utilização da função constructor é opcional. Ela é chamada durante a criação ou atualização do componente e pode ser utilizada para criação do ShadowRoot, criação de eventos. No entanto, ao usá-la, é necessário saber que há algumas restrições, são elas:

  • A função super deve ser invocada logo após a criação do construtor;
  • É proibido retornar um valor, exceto return (void) ou return this;
  • A utilização das funções document.write e document.open é proibida;
  • Os atributos e filhos do elemento não devem ser inspecionados; O elemento não deve ganhar nenhum atributo ou filho. Essas alterações violam o método createElement ao ser usado para criação;
  • Evitem trabalhar com renderização no construtor, optem pelo método connectedCallback;

Na linha 5, criamos o ShadowRoot. Nele, vamos adicionar os elementos necessário para a renderização. Há dois modos possíveis:

  • open: Permite que o código exterior tenha acesso aos elementos do componente usando o atributo shadowRoot, por exemplo:
document
 .querySelector('v-welcome')
 .shadowRoot
 .querySelector('div')
Enter fullscreen mode Exit fullscreen mode
  • closed: Não permite que o código exterior tenha acesso aos elementos filhos do componente.

Na linha 8, foi definida a função attributesChangedCallback, que será invocada sempre que houver uma adição, atualização, remoção ou substituição de atributos. Para receber tais atualizações, é necessário reescrever o método estático observedAttributes e retornar um array de strings com os atributos que serão "ouvidos" (linhas 30, 31 e 32) do código Código 01 - Base.

Na linha 16, temos o método connectedCallback, que será invocado quando o componente for adicionado ao DOM. Este método é recomendado para execução de códigos de instalação e renderização.

O método disconnectedCallback, linha 26, é executado no momento que o elemento for removido do DOM. É ideal para remoção de eventos e limpeza do componente.

Na linha 35, foi definido o nome do componente e a classe responsável por ele. É importante o nome seguir a regra "caracteres-nome_do_componente", dessa forma o navegador identificará que é um componente customizado.

Utilizando componente

Neste tópico, serão abordadas duas formas de utilização.

Via HTML

No HTML, basta carregar o arquivo de script (o lugar não é tão importante para o funcionamento, pode ser dentro do <head> ou no final do <body>). Após carregá-lo, basta utilizar a tag com o nome definido no primeiro parâmetro da função window.customElements.define

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="welcome.js" />
</head>
<body>
<v-welcome></v-welcome> <!-- Output "Olá, mundo" -->
<v-welcome name="Valdeir"></v-welcome> <!-- Output "Olá, Valdeir" -->
</body>
</html>
view raw welcome-01.html hosted with ❤ by GitHub

Via JavaScript

Você também pode usar a função document.createElement para criar o elemento e node.setAttribute('atributo', 'valor') para definir os valores necessários.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="welcome.js" />
</head>
<body>
<script>
const names = ['Jade', 'Mariana']
for (let name of names) {
const welcome = document.createElement('v-welcome')
welcome.setAttribute('name', name)
document.body.appendChild(welcome)
}
</script>
</body>
</html>
view raw welcome-02.html hosted with ❤ by GitHub

Resultado

Exemplo Adicional

Este é um exemplo um pouco mais complexo. Nele, utilizando o elemento <v-image> para carregar um placeholder enquanto a imagem principal não é carregada. Também adicionamos suporte a alguns filtros e efeitos com CSS.

GitHub do Projeto

Conclusão

É isso! Os componentes estão aí para serem explorados e utilizados, obviamente dependendo do projeto e seu público alvo. Eles são uma mão na roda e realmente auxiliam bastante.

Caso tenham alguma dica ou sugestão, é só comentar. Agradeço-os pela leitura.


Projetos que utilizam Web Components

Links úteis

Referências

MDN (org.). Using custom elements. In: MOZILLA. Using custom elements. [S. l.], [20 - ]. Disponível em: https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements. Acesso em: 3 jul. 2020.
WHATWG (org.). HTML: Scripting. [S. l.], [20 - ]. Disponível em: https://html.spec.whatwg.org/multipage/scripting.html. Acesso em: 8 jul. 2020.
WHATWG (org.). HTML: Custom elements. [S. l.], [20 - ]. Disponível em: https://html.spec.whatwg.org/multipage/custom-elements.html. Acesso em: 12 jul. 2020.
MDN (org.). Web Components: Using shadow DOM. [S. l.], [20 - ]. Disponível em: https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM. Acesso em: 12 jul. 2020.
W3C (org.). Shadow DOM. [S. l.], [20 - ]. Disponível em: https://www.w3.org/TR/shadow-dom/. Acesso em: 3 jul. 2020.
HANASHIRO, Akira. O que é DOM, Virtual DOM e Shadow DOM?. [S. l.], 17 abr. 2020. Disponível em: https://www.treinaweb.com.br/blog/o-que-e-dom-virtual-dom-e-shadow-dom/. Acesso em: 16 jul. 2020.
GLAZKOV, Dimitri. What the Heck is Shadow DOM?. [S. l.], 14 jan. 2011. Disponível em: https://glazkov.com/2011/01/14/what-the-heck-is-shadow-dom/. Acesso em: 16 jul. 2020.
https://github.com/mdn/web-components-examples

Top comments (0)

nextjs tutorial video

Youtube Tutorial Series 📺

So you built a Next.js app, but you need a clear view of the entire operation flow to be able to identify performance bottlenecks before you launch. But how do you get started? Get the essentials on tracing for Next.js from @nikolovlazar in this video series 👀

Watch the Youtube series

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay