Los elementos personalizados te permiten crear tus propias etiquetas HTML. Esta lista de tareas abarca prácticas recomendadas para ayudarte a crear elementos de alta calidad.
Los elementos personalizados te permiten extender el código HTML y definir tus propias etiquetas. Son un
función increíblemente potente, pero también son de bajo nivel, lo que significa que no es
siempre esté claro cuál es la mejor manera de implementar tu propio elemento.
Para ayudarte a crear las mejores experiencias posibles, reunimos esta
lista de tareas. Desglosa todo lo que creemos que hace falta
elemento personalizado con buen comportamiento.
Lista de tareas
Shadow DOM
  
    
      | Crea una shadow root para encapsular estilos. | 
    
      | ¿Por qué? | El encapsulamiento de estilos en la shadow root de tu elemento garantiza que funcione
  sin importar dónde se usen. Esto es muy importante si un desarrollador
  desea colocar tu elemento dentro de la shadow root de otro elemento. Esta
  se aplica incluso a elementos simples, como una casilla de verificación o un botón de selección. Podría ser
  en el caso de que el único contenido dentro de tu shadow root sean los estilos
  ellos mismos. | 
    
      | Ejemplo | El 
  elemento <howto-checkbox>. | 
  
  
    
      | Crea tu shadow root en el constructor. | 
    
      | ¿Por qué? | El constructor es cuando tienes conocimiento exclusivo de tu elemento.
  Es un buen momento para configurar los detalles de implementación que no quieres que otros
  elementos con los que se están mezclando. Hacer esto en una devolución de llamada posterior, como la connectedCallbacksignifica que deberás protegerte de
  situaciones en las que tu elemento se separa y, luego, se vuelve a adjuntar al documento. | 
    
      | Ejemplo | El 
  elemento <howto-checkbox>. | 
  
  
    
      | Coloca los elementos secundarios que el elemento cree en su shadow root. | 
    
      | ¿Por qué? | Los elementos secundarios que crea tu elemento forman parte de su implementación y deben
  privada. Sin la protección de una shadow root, fuera de JavaScript
  interferir inadvertidamente con estos niños. | 
    
      | Ejemplo | El 
  elemento <howto-tabs>. | 
  
  
    
      | Usar <slot> para proyectar elementos secundarios del Light DOM en tu shadow DOM | 
    
      | ¿Por qué? | Permitir que los usuarios de tu componente especifiquen contenido en él como elementos secundarios HTML hace que este sea más componible. Cuando un navegador no admite elementos personalizados, el contenido anidado permanece disponible, es visible y se puede acceder a él. | 
    
      | Ejemplo | El 
  elemento <howto-tabs>. | 
  
  
    
      | 
  Establece un estilo de visualización :host(p.ej.,block,inline-block,flex), a menos que prefieras la configuración predeterminada deinline | 
    
      | ¿Por qué? | Los elementos personalizados son display: inlinede forma predeterminada, por lo que establecer suwidthoheightno tendrán efecto. Esto a menudo
  sorprende a los desarrolladores y puede causar problemas relacionados con
  diseñar la página. A menos que prefieras una pantallainline,
  siempre debes establecer un valor predeterminado dedisplay. | 
    
      | Ejemplo | El 
  elemento <howto-checkbox>. | 
  
  
    
      | 
  Agrega un estilo de visualización :hostque respete el atributo oculto. | 
    
      | ¿Por qué? | Un elemento personalizado con un estilo displaypredeterminado, p.ej.,:host { display: block }, anulará la especificidad más baja
  integradohidden.
  Es posible que te sorprenda si esperas establecer lahidden.
  en tu elemento para renderizarlodisplay: none. Además,
  a un estilodisplaypredeterminado, agrega compatibilidad conhiddencon:host([hidden]) { display: none }. | 
    
      | Ejemplo | El 
  elemento <howto-checkbox>. | 
  
Atributos y propiedades
  
    
      | 
  No anules los atributos globales establecidos por el autor.
         | 
    
      | ¿Por qué? | Los atributos globales son aquellos que están presentes en todos los elementos HTML. Algunos
  algunos ejemplos incluyen tabindexyrole. Un elemento personalizado
  es posible que desee establecer sutabindexinicial en 0 para que sea de teclado
  enfocable. Pero siempre debes verificar primero si el desarrollador que usa
  tu elemento estableció esto en otro valor. Si, por ejemplo, se estableció
  Detabindexa -1, esto es un indicador de que no desea que el
  elemento para que sea interactivo. | 
    
      | Ejemplo | El 
  elemento <howto-checkbox>. Esto se explica con más detalle en
  No anules el autor de la página. | 
  
  
    
      | 
  Aceptar siempre datos primitivos (cadenas, números, booleanos) como cualquiera de los atributos
  o propiedades.
         | 
    
      | ¿Por qué? | Los elementos personalizados, al igual que sus equivalentes integrados, deben poder configurarse.
  La configuración se puede pasar de forma declarativa, a través de atributos o de forma imperativa
  a través de las propiedades de JavaScript. Idealmente, todos los atributos también deben estar vinculados a
  una propiedad correspondiente. | 
    
      | Ejemplo | El 
  elemento <howto-checkbox>. | 
  
  
    
      | 
  Tiene como objetivo mantener sincronizados los atributos y las propiedades de datos primitivos,
  a atribuir y viceversa.
         | 
    
      | ¿Por qué? | Nunca se sabe cómo un usuario interactuará con tu elemento. Quizás
  establecer una propiedad en JavaScript y, luego, esperar leer ese valor
  con una API como getAttribute(). Si cada atributo tiene un
  propiedad correspondiente y ambas se reflejan, para que sea más fácil para
  usuarios a trabajar con tu elemento. En otras palabras, llamarsetAttribute('foo', value)también debe establecer un valor
  propiedadfooy viceversa. Por supuesto, existen excepciones a
  esta regla. No deberías reflejar propiedades de alta frecuencia, p.ej.,currentTimeen un reproductor de video Usa tu mejor criterio. Si
  Parece que un usuario interactuará con una propiedad o un atributo.
  reflejarlo no es tedioso, entonces hazlo. | 
    
      | Ejemplo | El 
  elemento <howto-checkbox>. Esto se explica con más detalle en
  Evita los problemas de reentrada. | 
  
  
    
      | 
  Intenta aceptar solo datos enriquecidos (objetos, arrays) como propiedades.
         | 
    
      | ¿Por qué? | En términos generales, no hay ejemplos de elementos HTML integrados que
  aceptan datos enriquecidos (arrays y objetos simples de JavaScript) a través de sus
  atributos. En cambio, se aceptan datos enriquecidos mediante llamadas de método o
  propiedades. Hay algunas desventajas obvias al aceptar datos enriquecidos como
  atributos: puede ser costoso serializar un objeto grande en una cadena
  se perderán las referencias de objetos en este proceso de stringificación. Para
  ejemplo, si encadenas un objeto
que tiene referencia a otro,
  o un nodo del DOM, se perderán esas referencias. | 
  
  
    
      | 
  No se reflejan las propiedades de datos enriquecidos en los atributos.
         | 
    
      | ¿Por qué? | Reflejar las propiedades de los datos enriquecidos en atributos es innecesariamente costoso.
  que requieren serializar y deserializar los mismos objetos de JavaScript. Salvo que
  tienes un caso de uso que solo se puede resolver con esta función, probablemente sea
  es mejor evitarlo. | 
  
  
    
      | 
  Verifica las propiedades que podrían haberse establecido antes del elemento.
  actualizado.
         | 
    
      | ¿Por qué? | Un desarrollador que usa tu elemento puede intentar establecer una propiedad en él
  antes de que se cargue su definición. Esto es especialmente cierto si el
  desarrollador usa un framework que controla la carga de componentes y los sella
  a la página y vincular sus propiedades a un modelo. | 
    
      | Ejemplo | El 
  elemento <howto-checkbox>. Explicación más detallada en
  Haz que las propiedades sean diferidas. | 
  
  
    
      | 
  No apliques clases por tu cuenta.
         | 
    
      | ¿Por qué? | Los elementos que necesitan expresar su estado deben hacerlo mediante atributos. El
  Por lo general, el atributo classpertenece a la
  desarrollador usando tu elemento y escribir en él tú mismo puede
  para pisar fuerte
las clases de desarrolladores. | 
  
Eventos
  
    
      | 
  Eventos de despacho en respuesta a la actividad de componentes internos.
         | 
    
      | ¿Por qué? | Tu componente puede tener propiedades que cambian en respuesta a una actividad que
  que solo el componente conoce, por ejemplo, si un temporizador o una animación
  se complete o termine de cargarse un recurso. Es útil enviar eventos
  en respuesta a estos cambios para notificar al host que el estado del componente es
  es diferente. | 
  
  
    
      | 
  No despaches eventos en respuesta a la configuración del host en una propiedad (hacia abajo)
  flujo de datos).
         | 
    
      | ¿Por qué? | Enviar un evento en respuesta a la configuración del host de una propiedad es superfluo.
  (el host conoce el estado actual porque simplemente lo establece). Eventos de envío
  En respuesta a una configuración de host, una propiedad puede causar bucles infinitos de datos.
  de enlace de red. | 
    
      | Ejemplo | El 
  elemento <howto-checkbox>. | 
  
Explicaciones
No anular el autor de la página
Es posible que un desarrollador que usa tu elemento quiera anular algunos de
a su estado inicial. Por ejemplo, cambiar su role de ARIA o la enfocabilidad con
tabindex Verifica si se establecieron estos y otros atributos globales.
antes de aplicar tus propios valores.
connectedCallback() {
  if (!this.hasAttribute('role'))
    this.setAttribute('role', 'checkbox');
  if (!this.hasAttribute('tabindex'))
    this.setAttribute('tabindex', 0);
Haz que las propiedades sean diferidas
Un desarrollador puede intentar establecer una propiedad en tu elemento antes de su
se cargó la definición. Esto es especialmente cierto si el desarrollador usa un
framework que controla la carga de componentes, su inserción en la página y
que vinculan sus propiedades a un modelo.
En el siguiente ejemplo, Angular vincula declarativamente los atributos
la propiedad isChecked a la propiedad checked de la casilla de verificación. Si la definición de
la casilla de verificación del instructivo se cargó de forma diferida, es posible que Angular intente configurar
la propiedad marcada antes de que se actualice el elemento.
<howto-checkbox [checked]="defaults.isChecked"></howto-checkbox>
Un elemento personalizado debería manejar esta situación verificando si alguna propiedad tiene
ya se establecieron en su instancia. La <howto-checkbox>
demuestra este patrón mediante un método llamado _upgradeProperty().
connectedCallback() {
  ...
  this._upgradeProperty('checked');
}
_upgradeProperty(prop) {
  if (this.hasOwnProperty(prop)) {
    let value = this[prop];
    delete this[prop];
    this[prop] = value;
  }
}
_upgradeProperty() captura el valor de la instancia no actualizada y borra
la propiedad para que no oculte el propio establecedor de propiedades del elemento personalizado.
De esta manera, cuando finalmente se carga la definición del elemento, puede
reflejan el estado correcto.
Evita problemas de reentrada
Resulta tentador usar attributeChangedCallback() para reflejar el estado en un
propiedad subyacente, por ejemplo:
// When the [checked] attribute changes, set the checked property to match.
attributeChangedCallback(name, oldValue, newValue) {
  if (name === 'checked')
    this.checked = newValue;
}
Pero esto puede crear un bucle infinito si el establecedor de propiedades también se refleja en
el atributo.
set checked(value) {
  const isChecked = Boolean(value);
  if (isChecked)
    // OOPS! This will cause an infinite loop because it triggers the
    // attributeChangedCallback() which then sets this property again.
    this.setAttribute('checked', '');
  else
    this.removeAttribute('checked');
}
Una alternativa es permitir que el establecedor de propiedades se refleje en el atributo.
el método get determine su valor según el atributo.
set checked(value) {
  const isChecked = Boolean(value);
  if (isChecked)
    this.setAttribute('checked', '');
  else
    this.removeAttribute('checked');
}
get checked() {
  return this.hasAttribute('checked');
}
En este ejemplo, agregar o quitar el atributo también establecerá la propiedad.
Por último, attributeChangedCallback() se puede usar para controlar efectos secundarios
como aplicar estados de ARIA.
attributeChangedCallback(name, oldValue, newValue) {
  const hasValue = newValue !== null;
  switch (name) {
    case 'checked':
      // Note the attributeChangedCallback is only handling the *side effects*
      // of setting the attribute.
      this.setAttribute('aria-checked', hasValue);
      break;
    ...
  }
}