Felipe Moacir

Web Components: Nativos e Sem Framework

Web ComponentsVanilla JSStandards
Web Components: Nativos e Sem Framework

Web Components são componentes nativos do navegador. Sem React. Sem Vue. Só web standards.

As 3 APIs

Web Components são compostos por 3 specs:

  1. Custom Elements - Criar tags HTML customizadas
  2. Shadow DOM - Encapsulamento de CSS/JS
  3. HTML Templates - Templates reutilizáveis

Custom Elements

Criar um componente é estender HTMLElement:

class UserCard extends HTMLElement {
  connectedCallback() {
    const name = this.getAttribute('name');
    this.innerHTML = `
      <div class="card">
        <h2>${name}</h2>
        <button>Follow</button>
      </div>
    `;
  }
}

customElements.define('user-card', UserCard);

Uso no HTML:

<user-card name="Felipe Moacir"></user-card>

Shadow DOM: Encapsulamento Real

CSS do Shadow DOM não vaza para fora:

class FancyButton extends HTMLElement {
  connectedCallback() {
    const shadow = this.attachShadow({ mode: 'open' });
    
    shadow.innerHTML = `
      <style>
        button {
          background: linear-gradient(45deg, #667eea, #764ba2);
          color: white;
          border: none;
          padding: 12px 24px;
          border-radius: 8px;
        }
      </style>
      <button><slot></slot></button>
    `;
  }
}

customElements.define('fancy-button', FancyButton);

O CSS acima não afeta outros <button> da página.

Reactive Properties

Web Components podem ter propriedades reativas:

class CounterButton extends HTMLElement {
  static get observedAttributes() {
    return ['count'];
  }
  
  connectedCallback() {
    this.render();
    this.addEventListener('click', () => {
      const current = Number(this.getAttribute('count') || 0);
      this.setAttribute('count', String(current + 1));
    });
  }
  
  attributeChangedCallback(name, oldValue, newValue) {
    if (name === 'count') this.render();
  }
  
  render() {
    const count = this.getAttribute('count') || 0;
    this.innerHTML = `<button>Clicks: ${count}</button>`;
  }
}

customElements.define('counter-button', CounterButton);

Lifecycle Hooks

Web Components têm lifecycle similar aos frameworks:

  • connectedCallback() - Montado no DOM
  • disconnectedCallback() - Removido do DOM
  • attributeChangedCallback() - Atributo mudou
  • adoptedCallback() - Movido para outro documento

Quando Usar?

✅ Design Systems cross-framework
✅ Widgets embeddable (analytics, chat)
✅ Performance crítica (sem bundle)

❌ Apps complexos (sem routing, state)
❌ Precisa de SSR

Bibliotecas

Se quer DX melhor, use:

  • Lit - Templates, reatividade
  • Stencil - Compiler, TypeScript
  • FAST - Microsoft, performance
// Lit exemplo
import { LitElement, html, css } from 'lit';

class MyButton extends LitElement {
  static styles = css`button { color: blue; }`;
  
  render() {
    return html`<button><slot></slot></button>`;
  }
}

customElements.define('my-button', MyButton);

Conclusão: Web Components são o futuro para componentes universais. Mas frameworks ainda ganham para apps completos.