JavaScript
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Types
-
Section 3: Strings and Numbers in Depth
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Objects and Arrays
-
Section 7: Maps, Sets, and Symbols
-
Section 8: Asynchronous JavaScript
-
Section 9: Object-Oriented and Prototypes
-
Section 10: The DOM
-
Section 11: Browser APIs
-
Section 12: Modern JavaScript (ES2015-ES2025)
-
Section 13: Functional Programming Patterns
-
Section 14: Error Handling and Debugging
-
Section 15: Testing
-
Section 16: Accessibility for JavaScript Developers
-
Section 17: Internationalization and Localization
-
Section 18: Performance
-
Section 19: Node.js Fundamentals
-
Section 20: Regular Expressions
-
Section 21: Design Patterns in JavaScript
-
Section 22: Security Basics
-
Section 23: Data Structures and Algorithms in JavaScript
-
Section 24: Practical Projects
-
Section 25: More Advanced Async Patterns
-
Section 26: More Object and Class Practice
-
Section 27: Working with Dates and Internationalization
-
Section 28: Web Components
-
Section 29: More DOM and Browser Practice
-
Section 30: Build Tooling for Vanilla JavaScript
-
Section 31: More Practice Projects
-
Section 32: Interview and Algorithm Practice
-
Section 33: Error Objects (MDN Reference)
-
Section 34: TypedArrays and Binary Data
-
Section 35: Reflection and Metaprogramming (MDN Reference)
-
Section 36: More Global Functions (MDN Reference)
207: Custom Elements Basics
I've been building this dashboard project, and I noticed I'm repeating the same HTML structure over and over for user profile badges. You know the drill: a div, an image, a name, and a role. Every time I need one, I copy-paste a chunk of HTML and hope I don't mess up a class name. It feels clunky. I want a way to just write <user-badge> and have the browser handle the rest.
The "Wait, it's just a div" problem
My first instinct was to just start using a custom tag. I figured the browser might be smart enough to know what I mean. I tried this in my HTML:
<user-badge name="Alex" role="Lead Dev"></user-badge>
I refreshed the page and... nothing. Well, not "nothing," but the browser just treated it as a generic inline element. If I inspected it in the DevTools, it was there, but it had no styling and no logic. It's essentially just a <span> with a fancy name. The browser doesn't magically know how to render a <user-badge> because that tag isn't in the HTML specification. We have to define the behavior ourselves.
Giving the tag a brain
To make this work, I need a JavaScript class that tells the browser, "Hey, whenever you see this tag, use this logic." I started by extending the base HTMLElement class. I'll try to hook into the lifecycle of the element—specifically when it's actually added to the page.
class UserBadge extends HTMLElement {
connectedCallback() {
this.innerHTML = `<div class="badge">User Profile</div>`;
}
}
I added this to my script, refreshed, and... still nothing. I forgot the most important part: the registration. Creating the class is one thing, but the browser needs a map that links the string 'user-badge' to the UserBadge class. I added this line at the bottom:
customElements.define('user-badge', UserBadge);
Now, when I refresh, the text "User Profile" finally appears on the screen. It's a start, but it's static. Every single badge says the same thing, which defeats the purpose of having a name attribute in my HTML.
Making it dynamic with attributes
I want the badge to actually use the data I passed into the tag. Since I'm inside the class, this refers to the element itself. I can use getAttribute()` to pull those values out. Let's refine the connectedCallback.
class UserBadge extends HTMLElement {
connectedCallback() {
const name = this.getAttribute('name') || 'Unknown User';
const role = this.getAttribute('role') || 'Guest';
this.innerHTML = `
<div class="badge-container">
<strong>${name}</strong>
<small>${role}</small>
</div>
`;
}
}
customElements.define('user-badge', UserBadge);
Now, when I use <user-badge name="Alex" role="Lead Dev"></user-badge>, it actually renders "Alex" and "Lead Dev". This is the core of Custom Elements. I've essentially created my own HTML tag that encapsulates its own structure and data-handling logic. I can now drop this tag anywhere in my app, and as long as the script is loaded, it'll just work.
One thing to keep in mind: custom element names must contain a hyphen. If I had tried to call it <userbadge> (no hyphen), the browser would have thrown an error. This is a safety feature to ensure that custom elements never clash with future standard HTML tags that might be introduced to the language.
📋 Practical Task
Build a Custom Product Price Tag
Create a custom element called <product-price>. This element should take two attributes: price and currency.
- Define a class that extends
HTMLElement. - Use the
connectedCallbackto set theinnerHTMLof the element. - The output should be formatted as:
Price: [currency][price](e.g., Price: $99). - Register the element using
customElements.define. - Test it in your HTML by adding:
<product-price price="49.99" currency="€"></product-price>.
There are no comments for now.