Web Components: Criando componentes de forma agnóstica

Alexandre Servian
Comunidade XP
4 min readJun 9, 2021

--

Vamos conversar sobre o desenvolvimento web com web components e suas vantagens ao usá-los em seu próximo projeto.

Photo by Glen Carrie on Unsplash

No cotidiano de desenvolvimento front-end nos deparamos com vários desafios, como o de manter uma base de código sólida, separada por domínios e reutilizável.

No que se refere a reutilizável, buscamos sempre a melhor forma de manter um padrão de disponibilização de nossos componentes, para que os mesmos possam ser compartilhados com nossa equipe ou mesmo para outros times que muitas vezes trabalham com outros produtos dentro de uma mesma empresa.

Seguindo esta lógica, podemos ter vários desafios como: as equipes podem estar trabalhando com diferentes stack front-end como usar react, angular ou vue e ainda podemos ter projetos legados com stack front-end mais antigas como usando angularjs 1.x ou mesmo ember.js.

E ainda podemos ter um desafio extra como se o time optar em criar um design system para toda a empresa. Visto tais desafios listados, podemos optar em usar web components.

Web Components

Web components é uma terminologia usada para nomear um conjunto de tecnologias que possibilitam a criação de componentes customizados. Tais componentes customizados possuem certas vantagens como encapsular toda a camada lógica, de marcação e de apresentação em um único componente isolando sua funcionalidade dos demais componentes dentro de uma página.

Outra vantagem de se usar web components e o fato do desenvolvimento ser agnóstico, visto que um web component vai funcionar em qualquer lib como react ou framework como angular ou vue.

Suíte de apis que compõem os web components

Para a criação de um web component vamos usar basicamente 3 apis:

  • Custom element: api que tem como proposito criar tags html customizadas e prover um ciclo de vida ao componente.
  • Shadow DOM: usado para criar uma árvore DOM isolada da arvore DOM da página. Com ela podemos isolar toda nossa marcação, lógica e estilo.
  • Templates HTML: e por fim usar os elementos <template> e <slot>.

Custom Element

Com esta api podemos criar nossa tag personalizada e ainda ter acesso a um ciclo de vida para nosso componente.

Para registar uma nova tag basta:

window.customElements.define('todo-list', TodoList);

Sendo o primeiro parâmetro da função customElements.define o nome da tag. Esse nome deve seguir o padrão de escrita lower-kebab-case. Já o segundo parâmetro é a class contendo toda a regra do web component. Tal class temos que extender de HTMLElement.

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

E se tratando de ciclo de vida, podemos usar:

  • connectedCallback: invocado assim que o componente é atachado ao documento DOM;
  • disconnectedCallback: invocado sempre que o componente é removido do documento Dom;
  • attributeChangedCallback: invocado sempre que um atributo for removido, adicionado ou sofrer alteração.

Para definir quais atributos vão ser observados usamos o método estático observedAttributes() . Segue um exemplo:

class TodoList extends HTMLElement {
static get observedAttributes() {
return ["filter"];
}
attributeChangedCallback(name, oldValue, newValue) {
if (oldValue === newValue) {
return;
}
// Faça algum tratamento
}
}

Shadow DOM

Como falamos anteriormente, usamos o shadow Dom para criar nossa árvore DOM encapsulada. Podemos atachar nosso custom element para um shadow root da seguinte maneira:

class TodoList extends HTMLElement {
constructor() {
super();
this.root = this.attachShadow({ mode: 'open' });
}
}

O método attachShadow({mode: 'open'}) define que podemos acessar via javascript o shadow root do custom component. Podemos definí-lo como closed, porém não seremos capazes de acessar a shadow root de fora do custom component.

Podemos agora usar toda api DOM para manipular nosso web component, veja o exemplo:

class TodoList extends HTMLElement {
constructor() {
super();
this.root = this.attachShadow({ mode: 'open' });
}

connectedCallback() {
const template = `
<style>
:host {
background: orange;
display: flex;
width: 50px;
height: 50px;
}
</style>
<div class="container"></div>
`;
this.root.innerHTML = template;
this.$container = this.root.querySelector('.container');
}
}

Templates HTML

Podemos definir certas marcações HTML que podemos compartilhar com dezenas de componentes. Com isso em mente, podemos englobar a marcação que queremos compartilhar na tag <template> . Veja um exemplo:

let template = document.createElement('template');
template.innerHTML = `
<style>
:host {
background: orange;
display: flex;
width: 50px;
height: 50px;
}
</style>
<div class="container"></div>
`;
class TodoList extends HTMLElement {
constructor() {
super();
this.root = this.attachShadow({ mode: 'open' });
}

connectedCallback() {
this.root.appendChild(template.content.cloneNode(true));
this.$container = this.root.querySelector('.container');
}
}

E podemos usar tornar nosso web component ainda mais flexível usando <slot> ou <slot name="descricao"> . Visto que podemos inserir elementos dentro da nossa tag que representa nosso web components. Vejamos o seguinte exemplo:

<card-list>
<div slot="title">List languages</div>
<p>Javascript</p>
<p>Elixir</p>
<p>Csharp</p>
</card-list>

Para que os elementos children do card-list possam ser renderizados, podemos fazer o seguinte:

class CardList extends HTMLElement {
constructor() {
super();
this.root = this.attachShadow({ mode: 'open' });
}

connectedCallback() {
const template = `
<div class="container">
<slot name="title"></slot>
<div class="list>
<slot></slot>
</div>
</div>
`;
this.root.innerHTML = template;
}
}

Exemplo da criação de um web component

Para consolidar todo nosso conhecimento adquirido até aqui, nada melhor que um exemplo de um componente completo. Para exemplificar, vamos criar de praxe um to do list 😁.

Conclusão

Com isso finalizamos nosso estudo por web components. Existem outras formas de criar web components usando libs/compilers como:

Fiz dois exemplos, um que já apresentei no post:

O outro é usando stenciljs:

Obrigado por tudo até aqui galera. Vlws.

--

--

Alexandre Servian
Comunidade XP

Frontend programmer since 2010 with experience in SPA systems (‘single page application’) currently using react