Saltar al contenido

Elementos personalizados

Los Elementos personalizados representan uno de los pilares fundamentales de Web Components, lo que permite a los desarrolladores definir sus propias etiquetas y componentes HTML. Esta capacidad amplía el vocabulario HTML estándar, permitiendo la creación de elementos reutilizables y encapsulados con comportamiento personalizado. Profundicemos en el mundo de los Elementos personalizados y descubramos cómo aprovechar su poder.

Definir un Elemento personalizado

Para crear un elemento personalizado, utilizamos la sintaxis class en JavaScript para definir una nueva clase que extienda la clase incorporada HTMLElement. Esta clase encapsula el comportamiento y las propiedades del elemento. Una vez definida, la registramos en el navegador mediante customElements.define().

Ejemplo: Crear un Elemento personalizado simple


html
<my-custom-element></my-custom-element>
<script>
  class MyCustomElement extends HTMLElement {
    constructor() {
      super();
      this.attachShadow({ mode: 'open' });
      this.shadowRoot.innerHTML = `<p>Hello, World!</p>`;
    }
  }
  
  customElements.define('my-custom-element', MyCustomElement);
</script>

Este ejemplo define un elemento personalizado simple llamado my-custom-element que muestra "Hello, World!" dentro de un shadow DOM. Para usar este elemento, simplemente agrega <code><my-custom-element></code> a tu HTML.

nota

Custom Elements v1 es compatible con todos los navegadores modernos (Chrome 54+, Firefox 52+, Safari 10.1+, Edge 79+). Verifica siempre la compatibilidad del navegador si tienes como objetivo entornos heredados.

Callbacks del ciclo de vida

Los elementos personalizados tienen un conjunto de callbacks del ciclo de vida que permiten a los desarrolladores ejecutar código en puntos específicos del ciclo de vida del elemento:

  • connectedCallback(): Se invoca cada vez que el elemento personalizado se agrega a un elemento conectado al documento.
  • disconnectedCallback(): Se invoca cada vez que el elemento personalizado se desconecta del DOM del documento.
  • attributeChangedCallback(name, oldValue, newValue): Se invoca cada vez que se agrega, elimina o cambia uno de los atributos del elemento personalizado.
  • adoptedCallback(): Se invoca cada vez que el elemento personalizado se mueve a un nuevo documento.
CallbackCuándo se ejecuta
connectedCallback()El elemento se agrega al DOM
disconnectedCallback()El elemento se elimina del DOM
attributeChangedCallback(name, oldValue, newValue)Cambia un atributo observado
adoptedCallback()El elemento se mueve a un nuevo documento

Ejemplo: Usar callbacks del ciclo de vida


javascript
<lifecycle-element></lifecycle-element>
<script>
class LifecycleElement extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = `
      <style>
        #status {
          color: blue;
          font-weight: bold;
        }
      </style>
      <p>Lifecycle Element</p>
      <p id="status">Element not connected</p>
    `;
  }

  connectedCallback() {
    this.shadowRoot.getElementById('status').textContent = 'Element connected to the page.';
  }

  disconnectedCallback() {
    this.shadowRoot.getElementById('status').textContent = 'Element disconnected from the page.';
  }
}

customElements.define('lifecycle-element', LifecycleElement);
</script>

Atributos y propiedades

Los elementos personalizados pueden tener atributos y propiedades para gestionar su estado y comportamiento. Los atributos se establecen directamente en HTML y siempre son cadenas, mientras que las propiedades se establecen en el objeto DOM del elemento y pueden ser de cualquier tipo de dato. Ten en cuenta que attributeChangedCallback solo se ejecuta para los atributos listados explícitamente en el método static get observedAttributes() del elemento.

Ejemplo: Gestionar atributos y propiedades


javascript
<attribute-element id="element" data-content="Initial content"></attribute-element>
<button onclick="buttonClicked()">Click to change attribute</button>
<script>
  class AttributeElement extends HTMLElement {
    constructor() {
      super();
      this.attachShadow({ mode: 'open' });
      this.shadowRoot.innerHTML = `<p>Attribute Example: <span id="content"></span></p>`;
    }
  
    static get observedAttributes() {
      return ['data-content'];
    }
  
    attributeChangedCallback(name, oldValue, newValue) {
      if (name === 'data-content') {
        this.shadowRoot.getElementById('content').textContent = newValue;
      }
    }
  
    set content(value) {
      this.setAttribute('data-content', value);
    }
  
    get content() {
      return this.getAttribute('data-content');
    }
  }
  
  customElements.define('attribute-element', AttributeElement);

  function buttonClicked() {
    alert('button clicked!');
    const ourCustomElement = document.getElementById('element');
    ourCustomElement.content = 'New content';
  }
</script>

Aquí, el attribute-element actualiza su contenido en función del atributo data-content. La propiedad content proporciona una forma conveniente de obtener y establecer este atributo programáticamente.

Extender elementos incorporados

Los elementos personalizados pueden extender elementos HTML incorporados, añadiendo nueva funcionalidad mientras conservan su comportamiento original.

Ejemplo: Extender un elemento incorporado


javascript
<button is="fancy-button">Click me!</button>
<script>
  class FancyButton extends HTMLButtonElement {
    constructor() {
      super();
      this.addEventListener('click', () => {
        alert('Fancy button clicked!');
      });
    }
  }
  
  customElements.define('fancy-button', FancyButton, { extends: 'button' });
</script>

Aquí, fancy-button extiende el elemento estándar <button>, añadiendo un mensaje de alerta cuando se hace clic en el botón.

Mejores prácticas para Elementos personalizados

  1. Usar Shadow DOM: Encapsula siempre la estructura interna y los estilos de tu elemento personalizado utilizando el Shadow DOM.
  2. Definir APIs claras: Proporciona APIs claras e intuitivas para tus elementos personalizados a través de atributos y propiedades bien documentados.
  3. Gestión del ciclo de vida: Gestiona correctamente los callbacks del ciclo de vida del elemento para garantizar un comportamiento robusto y evitar fugas de memoria.
  4. Accesibilidad: Asegúrate de que tus elementos personalizados sean accesibles incluyendo roles y propiedades ARIA adecuados.
  5. Pruebas: Realiza pruebas exhaustivas de tus elementos personalizados en diferentes navegadores y entornos para garantizar compatibilidad y estabilidad.

Conclusión

Los elementos personalizados ofrecen una forma potente de extender HTML, lo que permite crear componentes reutilizables y encapsulados con comportamiento personalizado. Al aprovechar las características de los elementos personalizados, incluidos los callbacks del ciclo de vida, los atributos, las propiedades y el Shadow DOM, los desarrolladores pueden construir aplicaciones web sofisticadas y mantenibles.

Comienza a experimentar con elementos personalizados en tus proyectos hoy mismo y descubre nuevas posibilidades para el desarrollo web. Los ejemplos proporcionados aquí son solo el comienzo; úsalos como base para crear tus propios elementos personalizados innovadores.

Práctica

¿Cuáles de las siguientes afirmaciones sobre los elementos personalizados en JavaScript son verdaderas?

¿Te resulta útil?

Vista previa dual-run — compárala con las rutas Symfony en producción.