I'm attempting to create a web component that modifies the behavior and style of its child elements. However, I'd like to do this modification before the first render, so that no flickering occurs.
Below is a (hopefully) small example of a web component that this is intended to create content (identified by the content
class) that is hidden when the user clicks the header (identified by the trigger
class).
"use strict";
customElements.define(
"shrinkable-content",
class extends HTMLElement {
static observedAttributes = ["shrunk"];
constructor() {
super();
}
connectedCallback() {
setTimeout(() => {
const triggers = Array.from(this.getElementsByClassName("trigger"));
const contents = Array.from(this.getElementsByClassName("content"));
if (typeof this.shrunk === "undefined") {
this.shrunk = false;
}
contents.forEach( (content) => {
content.oldStyle = content.style.display;
if (this.shrunk) content.style.display = "none";
});
triggers.forEach((trigger) => {
trigger.style.cursor = "pointer";
trigger.addEventListener("click", (event) => {
this.shrunk = !this.shrunk;
contents.forEach((content) => {
content.style.display = this.shrunk ? "none" : content.oldStyle;
});
});
});
});
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'shrunk') this.shrunk = (newValue === "true") || (newValue === "");
}
}
);
<!DOCTYPE html>
<html lang="en-US">
<head>
<title>HTML + JavaScript</title>
<script src="./shrinkable-content.js"></script>
</head>
<body>
<ul>
<li>
<shrinkable-content shrunk>
<button class="trigger">Alpha Item</button>
<ul class="content">
<li>Item One</li>
<li>Item Two</li>
</ul>
</shrinkable-content>
</li>
</ul>
</body>
</html>
Notice the setTimeout()
call early in the connectedCallback()
function. I added that because without it, the function is called before the children are added/mounted. However, it also delays the execute until after the first render, resulting in flickering.
For some more context: I'm really trying to avoid the 'shadow' DOM approach here; it really goes against the design principals I'm trying to follow.
Edit: There have been a couple solutions presented for the 'shrinking' feature (which is appreciated), but the real question here is about the lifecycle of web components; The example is just to help discuss the issue/question.
Looks to me like you are rebuilding default HTML
<details>
and<summary>
Or wrapped in a more advanced Web Component, handling closing other opened
<details>