This morning, I had multiple people ask me how you can nest Web Components inside each other and share information from one to another. Today, we're going to look at how to do exactly that.
Let's dig in!
🤫 Shhh! I'm working on a new workshop-style course on Web Components. I don't even have a landing page for it yet, but if you buy my All-Access Pass, you'll get instant access to it as soon as its ready.
A silly Web Component
For this article, I've got a relatively pointless Web Component I've built, <wc-highlight>
.
<wc-highlight> <div>1</div> <div>2</div> <div>3</div> </wc-highlight>
When the Web Component instantiates, it…
- Gets all of the direct
.children
elements inside itself. - Sets the first item in that list (with an index of
0
) as the active
one. - Highlights the first item in the collection by setting
[aria-selected="true"]
.
customElements.define('wc-highlight', class extends HTMLElement { /** * Instantiate the custom element */ constructor () { // Always call super first in constructor super(); // Define properties this.boxes = Array.from(this.children); this.active = 0; // Set [aria-selected] // If the first element, set to true // Otherwise, set to false this.boxes.forEach(function (box, index) { box.setAttribute('aria-selected', index === 0 ? true : false); }); } });
I also have a .next()
method in the Web Component.
It increases this.active
by 1
(and resets it to 0
if you're at the end of the list). Then, it updates the [aria-selected]
attribute to highlight the new item.
/** * Skip to the next item */ next () { // Cache the currently active index let current = this.active; // Update active index this.active++; // If at the end, loop back to the start if (this.active === this.boxes.length) { this.active = 0; } // Update [aria-selected] this.boxes[current].setAttribute('aria-selected', false); this.boxes[this.active].setAttribute('aria-selected', true); }
By running it on the <wc-highlight>
element, you can shift highlighting from the current element to the next one in the list.
let highlight = document.querySelector('wc-highlight'); highlight.next();
Here's a demo.
Nesting a Web Component inside it
For a Web Component this simple, I'd typically have my controls to move to the next item as part of the component.
But on larger projects, it can be helpful to have a series of smaller-but-interconnected components that each handle one small piece of the UI and talk to each other.
For learning purposes, let's create a <wc-highlight-controls>
custom element inside our <wc-highlight>
Web Component constructor()
, and inject it into the DOM.
/** * Instantiate the custom element */ constructor () { // ... this.boxes.forEach(function (box, index) { box.setAttribute('aria-selected', index === 0 ? true : false); }); // Append controls let controls = document.createElement('wc-highlight-controls'); this.append(controls); }
Then, we can define <wc-highlight-controls>
as its own standalone Web Component.
customElements.define('wc-highlight-controls', class extends HTMLElement { /** * Instantiate the custom element */ constructor () { // Always call super first in constructor super(); // Do stuff... } });
Inside the constructor()
, we can use the Element.closest()
method to get the parent <wc-highlight>
element, and assign it to this.highlight
.
If no parent element is found, we'll bail early with the return
operator.
/** * Instantiate the custom element */ constructor () { // Always call super first in constructor super(); // Get parent <wc-highlight> element this.highlight = this.closest('wc-highlight'); if (!this.highlight) return; }
Next, we'll create a button
element, give it some text, and .append()
it inside our Web Component.
Then, we'll add a click
event listener to it.
/** * Instantiate the custom element */ constructor () { // Always call super first in constructor super(); // Get parent <wc-highlight> element this.highlight = this.closest('wc-highlight'); if (!this.highlight) return; // Create button this.button = document.createElement('button'); this.button.textContent = 'Next'; this.append(this.button); // Listen for button clicks this.button.addEventListener('click', this); }
Inside our handleEvent()
method, we'll run the .next()
method on this.highlight
to jump to the next item.
/** * Handle events * @param {Event} event The event object */ handleEvent (event) { this.highlight.next(); }
Here's another demo.
This is a very manual connection
This method relies on tightly coupled DOM elements.
It works, but it can be a bit fragile because it relies on specific elements loading in the right order and always have access to each other.
Tomorrow, we're going to look at a method I prefer: Custom Events.
These give you the ability to customize and share data between Web Components in a much more flexible, decoupled way.
They also allow developers to extend the Web Component in ways you might not think of or want to support directly when you create it.
Like this? You can support my work by purchasing an annual membership.
Cheers,
Chris
Want to share this with others or read it later? View it in a browser.
0 Komentar untuk "[Go Make Things] How to get different Web Components to talk to each other (part 1)"