20

This code gives an "Illegal Constructor" Error, can anybody tell me why?

class MyCustomElement extends HTMLElement {
  constructor(){
    super();
    // Other things
  }
}

const myFunc = () => {
  const instance = new MyCustomElement();
  console.log(instance);
}

myFunc();

1
  • The funny thing with the same issue on my site is that I immediately call customElements.define() after defining its class - and much later the call to document.createElement() fails because of this exact error. Commented Dec 10, 2023 at 15:01

3 Answers 3

28

After hours of searching I found that you MUST register the custom element BEFORE you can create an instance of it. I don't think this is in the spec, but this is the case for all browsers, also the error message sucks. I wish chrome would have just said "You must register a custom element before instantiating it" rather than "Illegal Constructor", which tells us almost nothing about what actually went wrong.

class MyCustomElement extends HTMLElement {
  constructor(){
    super();
    // Other things
  }
}

const myFunc = () => {
  const instance = new MyCustomElement();
  console.log(instance);
}

// Add this and it will start working
window.customElements.define('my-custom-element', MyCustomElement);

myFunc();

Sign up to request clarification or add additional context in comments.

4 Comments

If you to new any built in HTMLElement, this error will be raised. Defining the custom element in the registry works around this somehow, but the error you observed is actually raised when the superclass constructor is newed.
Just want to know when we need this kind of custom element ?
@SandeshSapkota This element is just an example for this question, it doesn't actually do anything. If your asking what custom elements are for you should probably google it, they are amazing.
Note (for completeness) that this behavior is specced here: html.spec.whatwg.org/#html-element-constructors
4

It worked for me when I added {extends: 'div'} to the options which is the third parameter to the define method, so my code was like this

class MyCustomElement extends HTMLDivElement {
  constructor(){
    super()
  }

  connectedCallback() {
    console.log("Custom element added to page.");
  }
}

window.customElements.define('my-custom-element', MyCustomElement, {extends: 'div'})

// then I exported it and used it in another class
export default MyCustomElement;

and I used it like so

// another-file.js

import MyCustomElement from '../path/to/custom-element-class-file.js'

//...
const customDiv = new MyCustomElement()

document.body.append(customDiv)

//...

even the connectedCallback method was called after the element got added to the DOM

2 Comments

Great! I tried it with "button". But my <custome-button> became a regular <button>. So I'll be switching to extends HTMLElement. :)
@LSR I also later changed back to using HTMLElement because of the same reason, my custom div was showing as a regular div so I changed to using HTMLElement and extended HTMLDivElement, like so class MyCustomElement extends HTMLElement implements HTMLDivElement and then I removed the third parameter from customElements.define()
3

Note that you can create a custom element before it is defined by using document.createElement().

This element will be created as an unknown element and then only upgrade to a custom element when defined.

class MyCustomElement extends HTMLElement {
  constructor(){
    super()
    console.log( 'created' )
  }
}

const myFunc = () => {
  const instance = document.createElement( 'my-custom-element' )
  console.log( instance )
  document.body.appendChild( instance )
}

myFunc()

customElements.define( 'my-custom-element', MyCustomElement )

3 Comments

hi just wondering, do you think it's bad practice to use document.querySelector() to get another custom element inside of a custom element? example: Two web component /custom element inside of the normal document and inside of componentA, I use document.querySelector('componentB') to get componentB and do something with componentB, thanks
@MrBear77 of course you can do it. Note that if they use ShadowDOM you'll have to get the shadowRoot reference before.
including using this way to pass data? like this code example: stackoverflow.com/questions/62373477/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.