Com os elementos personalizados, você pode criar suas próprias tags HTML. Esta lista de verificação abrange as práticas recomendadas para ajudar você a criar elementos de alta qualidade.
Com os elementos personalizados, você pode estender o HTML e definir suas próprias tags. Eles são
incrivelmente eficiente, mas também são de baixo nível, o que significa que não são
sempre claro a melhor forma de implementar seu próprio elemento.
Para ajudar você a criar as melhores experiências possíveis, reunimos esta
lista de verificação. Ele detalha tudo que achamos que é preciso para ser um
um elemento personalizado bem-comportado.
Lista de verificação
Shadow DOM
  
    
      | Crie uma raiz paralela para encapsular estilos. | 
    
      | Por quê? | O encapsulamento de estilos na raiz paralela do elemento garante que ele funcione
  independentemente de onde eles são usados. Isso é importante principalmente se um desenvolvedor
  quer colocar seu elemento dentro da raiz paralela de outro elemento. Isso
  se aplica até mesmo a elementos simples, como uma caixa de seleção ou um botão de opção. Pode ser
  caso o único conteúdo da sua raiz paralela serão os estilos
  por conta própria. | 
    
      | Exemplo | O <howto-checkbox>. | 
  
  
    
      | Crie sua raiz paralela no construtor. | 
    
      | Por quê? | O construtor é quando você tem conhecimento exclusivo do seu elemento.
  Este é um ótimo momento para configurar detalhes de implementação que você não quer que outras
  com os elementos. Fazer esse trabalho em um retorno de chamada posterior, como o connectedCallback, significa que você vai precisar se proteger contra
  situações em que o elemento é desconectado e reanexado ao documento. | 
    
      | Exemplo | O <howto-checkbox>. | 
  
  
    
      | Coloque os filhos que o elemento criar na raiz paralela. | 
    
      | Por quê? | Os filhos criados pelo seu elemento fazem parte da implementação e devem ser
  privados. Sem a proteção de uma raiz paralela, o JavaScript externo pode
  interferir inadvertidamente nessas crianças. | 
    
      | Exemplo | O <howto-tabs>. | 
  
  
    
      | Usar <slot> para projetar filhos do light DOM no shadow DOM | 
    
      | Por quê? | Permite que os usuários do componente especifiquem conteúdo nele, já que os filhos do HTML tornam o componente mais combinável. Quando um navegador não aceita elementos personalizados, o conteúdo aninhado permanece disponível, visível e acessível. | 
    
      | Exemplo | O <howto-tabs>. | 
  
  
    
      | 
  Defina um estilo de exibição para :host(por exemplo,block,inline-block,flex), a menos que você prefira o padrão deinline. | 
    
      | Por quê? | Os elementos personalizados são display: inlinepor padrão. Portanto, definir oswidthouheightnão terão efeito. Isso muitas vezes
  é uma surpresa para os desenvolvedores e pode causar problemas relacionados a
  o layout da página. A menos que você prefira uma telainline,
  precisa sempre definir um valordisplaypadrão. | 
    
      | Exemplo | O <howto-checkbox>. | 
  
  
    
      | 
  Adicione um estilo de exibição :hostque respeite o atributo oculto. | 
    
      | Por quê? | Um elemento personalizado com um estilo displaypadrão, por exemplo::host { display: block }, substituirá a menor especificidade
  integradohidden.
  Isso pode surpreender se você pretende definir ohiddenno seu elemento para renderizá-lo comodisplay: none. Além disso,
  para um estilodisplaypadrão, adicione suporte parahiddencom:host([hidden]) { display: none }. | 
    
      | Exemplo | O <howto-checkbox>. | 
  
Atributos e propriedades
  
    
      | 
  Não substitua os atributos globais definidos pelo autor.
         | 
    
      | Por quê? | Atributos globais são aqueles que estão presentes em todos os elementos HTML. Algumas
  como tabindexerole. Um elemento personalizado
  pode definir otabindexinicial como 0 para que seja teclado
  focalizável. Mas você deve sempre verificar primeiro se o desenvolvedor que usa
  o elemento definiu isso com outro valor. Se, por exemplo, ele tiver definidotabindexa -1, é um sinal de que a pessoa não quer
  elemento para ser interativo. | 
    
      | Exemplo | O <howto-checkbox>. Isso é explicado em mais detalhes
  Não substitua o autor da página. | 
  
  
    
      | 
  Sempre aceite dados primitivos (strings, números, booleanos) como atributos
  ou propriedades.
         | 
    
      | Por quê? | Os elementos personalizados, assim como os integrados, precisam ser configuráveis.
  A configuração pode ser transmitida de maneira declarativa, por atributos ou
  usando propriedades JavaScript. O ideal é que todos os atributos também estejam vinculados
  uma propriedade correspondente. | 
    
      | Exemplo | O <howto-checkbox>. | 
  
  
    
      | 
  Procure manter os atributos e as propriedades de dados primitivos em sincronia, refletindo a partir da
  para atribuir a propriedade e vice-versa.
         | 
    
      | Por quê? | Nunca se sabe como um usuário vai interagir com seu elemento. Eles poderiam
  uma propriedade em JavaScript e vai ler esse valor
  usando uma API, como getAttribute(). Se cada atributo tiver um
  propriedade correspondente e ambas refletirem, facilitará para que
  que os usuários trabalhem com seu elemento. Em outras palavras, chamarsetAttribute('foo', value)também precisa definirfooe vice-versa. É claro que há exceções
  essa regra. Não inclua propriedades de alta frequência, por exemplo,currentTimeem um player de vídeo. Use seu bom senso. Se
  parece que um usuário vai interagir com uma propriedade ou um atributo, e
  não é trabalhoso refletir isso, então faça isso. | 
    
      | Exemplo | O <howto-checkbox>. Isso é explicado em mais detalhes
  Evite problemas de reentrada: | 
  
  
    
      | 
  Procure aceitar apenas dados avançados (objetos, matrizes) como propriedades.
         | 
    
      | Por quê? | De modo geral, não há exemplos de elementos HTML integrados que
  aceitam dados avançados (objetos e matrizes JavaScript simples) por meio de
  atributos. Os dados avançados são aceitos por chamadas de método ou
  propriedades. Há algumas desvantagens óbvias em aceitar dados avançados
  atributos: pode ser caro serializar um objeto grande em uma string e
  quaisquer referências de objetos serão perdidas nesse processo de string. Para
  exemplo, se você criar uma string para um objeto que tem uma referência a outro objeto,
  ou talvez um nó DOM, essas referências serão perdidas. | 
  
  
    
      | 
  Não refletem propriedades de dados avançados para atributos.
         | 
    
      | Por quê? | Refletir propriedades de dados avançados em atributos é caro,
  exigindo a serialização e desserialização dos mesmos objetos JavaScript. A menos que
  você tem um caso de uso que só pode ser resolvido com esse recurso, provavelmente é
  melhor evitá-lo. | 
  
  
    
      | 
  Verifique se há propriedades definidas antes do elemento
  atualizado.
         | 
    
      | Por quê? | Um desenvolvedor que usa seu elemento pode tentar definir uma propriedade no elemento.
  antes do carregamento da definição. Isso é especialmente verdadeiro se
  desenvolvedor está usando um framework que lida com o carregamento de componentes, carimbando-os
  à página e vincular as propriedades a um modelo. | 
    
      | Exemplo | O <howto-checkbox>. Mais explicados em
  Torne as propriedades lentas. | 
  
  
    
      | 
  Não aplique turmas automaticamente.
         | 
    
      | Por quê? | Elementos que precisam expressar o estado precisam usar atributos. A
  O atributo classgeralmente é considerado de propriedade do
  usando seu elemento. Além disso, gravar nele por conta própria pode
  participar de aulas para desenvolvedores. | 
  
Eventos
  
    
      | 
  Enviar eventos em resposta à atividade do componente interno.
         | 
    
      | Por quê? | Seu componente pode ter propriedades que mudam em resposta à atividade que
  que somente seu componente conhece, por exemplo, se um cronômetro ou animação
  é concluída ou um recurso termina de carregar. É útil enviar eventos
  em resposta a essas alterações, para notificar o host de que o estado do componente foi
  diferente. | 
  
  
    
      | 
  Não envie eventos em resposta à definição do host de uma propriedade (para baixo
  fluxo de dados).
         | 
    
      | Por quê? | Envio de um evento em resposta a uma configuração de host de uma propriedade é desnecessário
  (o host sabe o estado atual porque acabou de defini-lo). Eventos de envio
  em resposta à definição de um host, uma propriedade pode causar loops infinitos com
  sistemas de vinculação. | 
    
      | Exemplo | O <howto-checkbox>. | 
  
Vídeos de explicação
Não substituir o autor da página
É possível que um desenvolvedor que use seu elemento queira modificar algumas
o estado inicial dela. Por exemplo, mudar a role ARIA ou a capacidade de foco com
tabindex. Verifique se esses e outros atributos globais foram definidos.
antes de aplicar seus próprios valores.
connectedCallback() {
  if (!this.hasAttribute('role'))
    this.setAttribute('role', 'checkbox');
  if (!this.hasAttribute('tabindex'))
    this.setAttribute('tabindex', 0);
Tornar as propriedades lentas
Um desenvolvedor pode tentar definir uma propriedade no seu elemento antes que o
foi carregada. Isso é especialmente verdadeiro se o desenvolvedor estiver usando um
que lida com o carregamento de componentes, inserindo-os na página e
vinculando as propriedades a um modelo.
No exemplo a seguir, o Angular vincula de forma declarativa o
isChecked à propriedade checked da caixa de seleção. Se a definição de
a caixa de seleção de instruções foi carregada lentamente. É possível que o Angular tente definir
a propriedade marcada antes do upgrade do elemento.
<howto-checkbox [checked]="defaults.isChecked"></howto-checkbox>
Um elemento personalizado deve lidar com esse cenário verificando se alguma propriedade tem
já foi definido na instância. O <howto-checkbox>
demonstra esse padrão usando um método chamado _upgradeProperty().
connectedCallback() {
  ...
  this._upgradeProperty('checked');
}
_upgradeProperty(prop) {
  if (this.hasOwnProperty(prop)) {
    let value = this[prop];
    delete this[prop];
    this[prop] = value;
  }
}
_upgradeProperty() captura o valor da instância não atualizada e exclui
a propriedade para que ela não sombre o configurador de propriedades do próprio elemento personalizado.
Dessa forma, quando a definição do elemento for finalmente carregada, ela poderá
refletem o estado correto.
Evitar problemas de reentrada
É tentador usar attributeChangedCallback() para refletir o estado de uma
propriedade subjacente, por exemplo:
// When the [checked] attribute changes, set the checked property to match.
attributeChangedCallback(name, oldValue, newValue) {
  if (name === 'checked')
    this.checked = newValue;
}
Mas isso pode criar um loop infinito se o setter da propriedade também refletir
o 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');
}
Uma alternativa é permitir que o setter da propriedade reflita o atributo, e
faça com que o getter determine seu valor com base no atributo.
set checked(value) {
  const isChecked = Boolean(value);
  if (isChecked)
    this.setAttribute('checked', '');
  else
    this.removeAttribute('checked');
}
get checked() {
  return this.hasAttribute('checked');
}
Nesse exemplo, a adição ou remoção do atributo também definirá a propriedade.
Por fim, o attributeChangedCallback() pode ser usado para processar efeitos colaterais
como aplicar estados 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;
    ...
  }
}