JavaScript Academy · Lesson

Defining Custom Elements

Register elements with the customElements API.

Lesson 1 of 413 steps

Defining Custom Elements is a free JavaScript Academy lesson on CoddyKit. This is lesson 1 of 4. Any 3 lessons of this learning path are free to read in full — after that, CoddyKit PRO unlocks every lesson, plus hands-on practice with a built-in code editor and a 24/7 AI tutor. It is part of the JavaScript Academy learning path, and your progress syncs across the web and the CoddyKit app. The JavaScript Academy course includes 4 lessons in total.

What Are Custom Elements?

Custom elements let you define your own HTML tags backed by JavaScript classes. Instead of gluing together div soup, you create a reusable, self-contained component like <user-card>.

  • They are part of the Web Components standard.
  • They work natively in browsers, no framework required.
  • A custom element name must contain a hyphen (e.g. my-button).

The customElements Registry

The browser exposes a global registry at window.customElements. You register a new tag by calling customElements.define(name, constructor).

Once defined, every matching tag in the document is upgraded into an instance of your class.

// Register a tag named 'hello-world'
customElements.define('hello-world', HelloWorld);

// After this, every <hello-world> in the page
// becomes an instance of the HelloWorld class.

Extending HTMLElement

A custom element is a class that extends HTMLElement. The base class gives your element all standard DOM capabilities (attributes, events, styling).

Always call super() first in the constructor so the element is properly initialized.

class HelloWorld extends HTMLElement {
  constructor() {
    super(); // required, sets up the element
  }
}

customElements.define('hello-world', HelloWorld);

Rendering Content

Inside the element you can set this.innerHTML or use DOM methods to build content. A common pattern is to render when the element is connected to the page.

class HelloWorld extends HTMLElement {
  connectedCallback() {
    this.innerHTML = '<p>Hello from a custom element!</p>';
  }
}

customElements.define('hello-world', HelloWorld);

Using the Element in HTML

After registration, use your tag just like any built-in element. You can place it directly in markup or create it with document.createElement.

// In HTML:
// <hello-world></hello-world>

// Or in JavaScript:
const el = document.createElement('hello-world');
document.body.appendChild(el);

The Constructor's Rules

The constructor runs when an instance is created. There are strict rules:

  • Call super() first.
  • Do not inspect or add attributes/children here.
  • Defer DOM work to connectedCallback.

Use the constructor only for initial state and event listener setup.

class CounterButton extends HTMLElement {
  constructor() {
    super();
    this.count = 0; // safe: just internal state
  }
}

customElements.define('counter-button', CounterButton);

Adding Behavior

Because your element is a real DOM node, you can attach event listeners and update its content in response to interaction.

class CounterButton extends HTMLElement {
  constructor() {
    super();
    this.count = 0;
  }
  connectedCallback() {
    this.textContent = 'Clicked 0 times';
    this.addEventListener('click', () => {
      this.count++;
      this.textContent = 'Clicked ' + this.count + ' times';
    });
  }
}
customElements.define('counter-button', CounterButton);

The Hyphen Requirement

Custom element names must include a dash. This guarantees they never clash with current or future built-in HTML elements.

  • my-widget is valid.
  • mywidget is invalid and throws an error.
  • Names are case-insensitive but written lowercase.
// Valid:
customElements.define('app-header', AppHeader);

// Invalid - throws SyntaxError (no hyphen):
// customElements.define('appheader', AppHeader);

whenDefined and get

Two useful registry methods:

  • customElements.get(name) returns the constructor, or undefined if not registered.
  • customElements.whenDefined(name) returns a Promise that resolves once the element is defined.
customElements.whenDefined('hello-world').then(() => {
  console.log('hello-world is ready to use');
});

const Ctor = customElements.get('hello-world');

Defining Only Once

Each name can be registered only once. Calling define with an already-used name throws. Guard against double registration in shared modules.

if (!customElements.get('hello-world')) {
  customElements.define('hello-world', HelloWorld);
}

Why Custom Elements Matter

Custom elements give you framework-agnostic, encapsulated, reusable UI. They:

  • Standardize component reuse across any stack.
  • Integrate with the browser's own lifecycle.
  • Pair naturally with Shadow DOM and templates (covered later).

Quick Check

Test your understanding of defining custom elements.

Recap

You learned how to define custom elements:

  • customElements.define(name, class) registers a tag.
  • The class extends HTMLElement and calls super() first.
  • Names must include a hyphen.
  • Render content in connectedCallback, not the constructor.
  • get and whenDefined help you check registration status.

Next, we explore the full lifecycle of a custom element.

Free to start

Learn JavaScript with an AI tutor — free

Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.

Courses
59
Lessons
200

Frequently Asked Questions

Is the “Defining Custom Elements” lesson free?

Yes — any 3 lessons of the JavaScript Academy learning path, including “Defining Custom Elements”, are free to read in full here on the web. After that, CoddyKit PRO unlocks every lesson, plus interactive practice with a built-in code editor and a 24/7 AI tutor. The JavaScript Academy course includes 4 lessons in total.

What will I learn in “Defining Custom Elements”?

Register elements with the customElements API. You practise JavaScript Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start JavaScript Academy?

No prior experience is required. JavaScript Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 1 of 4.

How long does the “Defining Custom Elements” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this JavaScript Academy lesson?

Yes. Every JavaScript Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Defining Custom Elements
  2. Lifecycle Callbacks
  3. Shadow DOM and Encapsulation
  4. Templates and Slots
← Back to JavaScript Academy