- Published on
Cómo escribir un Web Component desde cero
- Authors

- Name
- Diego Whiskey
Escribir un Web Component
- sin frameworks
- sin helpers
- sin magia
- como lo ejecuta el navegador
1. El mínimo absoluto
Un Web Component empieza con una clase y un registro.
class CExample extends HTMLElement {}
customElements.define('c-example', CExample);
Nada más.
Si esto no existe:
<c-example>es HTML inválido- el navegador no sabe qué hacer
2. Error común #1: olvidar el guion
customElements.define('cexample', CExample); // ❌
Los Custom Elements deben tener guion.
Esto evita colisiones con HTML nativo.
3. Constructor: qué sí y qué no
class CExample extends HTMLElement {
constructor() {
super();
}
}
Regla crítica
Siempre llamar
super()primero.
Si no:
- el elemento no se inicializa
- el error es silencioso
Qué NO hacer en el constructor
❌ Acceder al DOM externo ❌ Leer atributos finales ❌ Renderizar contenido complejo
El elemento aún no está en el DOM.
4. connectedCallback: el verdadero inicio
connectedCallback() {
console.log('Elemento conectado al DOM');
}
Aquí sí:
- el elemento existe en el DOM
- los atributos ya están disponibles
En Caridad UI, el render inicial ocurre aquí.
5. Shadow DOM mínimo
connectedCallback() {
if (this.shadowRoot) return;
this.attachShadow({ mode: 'open' });
}
Error común:
- crear múltiples shadowRoots
Este guard es obligatorio.
6. Render real (sin innerHTML)
const template = document.createElement('template');
template.innerHTML = `
<style>
:host { display: block; }
</style>
<div class="content">
<slot></slot>
</div>
`;
connectedCallback() {
if (!this.shadowRoot) {
this.attachShadow({ mode: 'open' });
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
}
Nota importante:
innerHTMLsolo se usa con HTML controlado (el template)- nunca con input externo
7. Error común #2: renderizar múltiples veces
connectedCallback() {
this.render(); // ❌ sin control
}
Esto duplica nodos si el elemento se reconecta.
Solución:
- render una sola vez
- luego actualizar nodos puntuales
8. Atributos observados
static get observedAttributes() {
return ['disabled'];
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'disabled') {
this.toggleAttribute('aria-disabled', newValue !== null);
}
}
Reglas:
- atributos son string o null
- no usar lógica pesada aquí
9. Propiedades vs atributos (error clásico)
❌ Esto es incorrecto:
this.setAttribute('value', obj);
✔ Correcto:
this.value = obj;
Atributos:
- configuración inicial
- interoperabilidad HTML
Propiedades:
- estado interno
- objetos
10. Limpieza: disconnectedCallback
disconnectedCallback() {
this.removeEventListener('click', this.onClick);
}
Error común:
- olvidar limpiar listeners
- memory leaks silenciosos
11. Componente mínimo funcional
class CBox extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
if (this.shadowRoot.children.length) return;
const div = document.createElement('div');
div.textContent = 'Hola desde CBox';
this.shadowRoot.appendChild(div);
}
}
customElements.define('c-box', CBox);
Eso es un Web Component real.
12. Posición técnica
Un Web Component bien escrito:
- tiene poco código
- tiene reglas claras
- falla de forma visible
En Caridad UI:
Primero control. Luego ergonomía.
Nunca al revés.