skip to Main Content

I’m trying to make an HTML page which has the list of all the anime I watched and am about to watch. So, I was trying to make an <anime> tag for convenience purpose. It has name and time attributes. Here is the code for the custom elements:

Expected output: □ □ One Piece (15 Days)

Running this is giving the following error: Uncaught DOMException: CustomElementRegistry.define: 'anime' is not a valid custom element name

I’ve researched about valid custom element names, and this satisfies all those rules:

  1. any letter/symbol except capital letters
  2. start with lower case letter
  3. hyphens for spaces to separate words (here the name is only one word though)
class Anime extends HTMLDivElement {
  constructor() {
    super();

    let name = this.getAttribute("name");
    let time = this.getAttribute("time");

    let children = [document.createElement("input"), document.createElement("input"), document.createElement("span"), document.createElement("b")];
    children[0].type = "checkbox";
    children[1].type = "checkbox";
    children[3].innerHTML = name;
    children[2].append(children[3]);
    children[2].append(` ${time}`);
    this.append(children[0], children[1], children[2]);
  }
}

customElements.define("anime", Anime);
<anime name="One Piece" time="15 Days">

2

Answers


  1. Name of the custom element must start with a lowercase letter, contain a hyphen, and satisfy certain other rules listed in the in the specification’s definition of a valid name

    Syntax

    [a-z]* ‘-‘ [a-z]*

    customElements.define("anime-element", Anime);  //✅
    

    In HTML

    <anime-element name="One Piece" time="15 Days"></anime-element>
    
    Login or Signup to reply.
    • You can’t do DOM operations in the constructor. As there might not be DOM.(eg when elements are defined before DOM is parsed)
      Easily tested by executing a document.createElement("a-element") in the DEV console. (note: many "guru" developers get this wrong too, because they use the not required defer/async on their <script> calls without understanding what it does)
      Long read: My DEV.to blog on the connectedCallback

    • Do DOM operations in the connectedCallback that’s the signal the element appeared in the DOM

    • extend HTMLDIVElement (or any existing Element) is called a Customized Built-In Element and will never be supported in the (Apple) Safari Browser.
      Stick to Autonomous Elements extend HTMLElement unless you only deliver to Chromium and FireFox.
      My StackOverflow post on this

    • An "empty" constructor

        constructor() {  
          super()
        }
      

      is pointless, as a class by default "super" calls its parent (in this case the constructor in HTMLElement)

    • Use a helper function createElement so props and Eventlisteners can easily be set and your code doesn’t look like a dropped spaghetti dish.

    • Custom Elements (aka Web Components) must be closed with a closing tag <a-element></a-element>

    • the defining class can be an anonymous class inside the define function. You rarely want a Named class.

    HTH

    const createElement = (t,p={}) => Object.assign(document.createElement(t),p);
    
    customElements.define("a-element", class extends HTMLElement {
      connectedCallback() {
        let name = this.getAttribute("name") || "no name attribute";
        let time = this.getAttribute("time") || "no time attribute";
        this.append(
          this.inp1 = createElement("input", {
            type: "checkbox",
            id: "first",
            onclick: (evt) => {
              alert("clicked input" + this.inp1.id);
            }
          }),
          createElement("input",{
            type: "checkbox"
          }),
          createElement("span",{
            innerHTML: `${name} <b>${time}</b>`
          })
        );
      }
    });
    <a-element name="One Piece" time="15 Days"></a-element>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search