Skip to content

Instantly share code, notes, and snippets.

@pmdartus
Created December 9, 2021 17:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pmdartus/cd490a82617e025a2e73f79f7f9888b3 to your computer and use it in GitHub Desktop.
Save pmdartus/cd490a82617e025a2e73f79f7f9888b3 to your computer and use it in GitHub Desktop.
Scoped slot allocation and shadow DOM
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Scoped slot with declarative allocation</title>
</head>
<body>
<x-list></x-list>
<script>
customElements.define(
"x-list",
class extends HTMLElement {
#values = [];
#tmpl;
constructor() {
super();
const shadowRoot = this.attachShadow({
mode: "open",
});
this.shadowRoot.innerHTML = `<div></div>`;
}
set template(tmpl) {
this.#tmpl = tmpl;
this.#rerender();
}
get template() {
return this.#tmpl;
}
set values(v) {
this.#values = v;
this.#rerender();
}
get values() {
return this.#values;
}
#rerender() {
if (!this.#tmpl || !this.#values) {
return;
}
const container = this.shadowRoot.querySelector("div");
const slots = [];
// Remove all the slots
while (container.firstChild) {
container.firstChild.remove();
}
// Remove all the existing children
while (this.firstChild) {
this.firstChild.remove();
}
// Render all the slots
for (let i = 0; i < this.#values.length; i++) {
const slot = document.createElement("slot");
slot.name = `__scoped-${i}`;
slots.push(slot);
container.appendChild(slot);
}
// Render all the scoped slotted content.
for (let i = 0; i < this.#values.length; i++) {
const tmpElm = document.createElement("template");
tmpElm.innerHTML = this.#tmpl(this.#values[i]);
this.appendChild(tmpElm.content);
this.lastChild.setAttribute('slot', slots[i].name);
}
}
}
);
const list = document.querySelector("x-list");
list.template = (item) => {
return `<div>${item.id} - ${item.name}</div>`;
};
list.values = [
{
id: 1,
name: "Buy groceries",
},
{
id: 2,
name: "Clean up my desk",
},
{
id: 3,
name: "Do the laundry",
},
];
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Scoped slot with declarative allocation</title>
</head>
<body>
<x-list></x-list>
<script>
customElements.define(
"x-list",
class extends HTMLElement {
#values = [];
#tmpl;
constructor() {
super();
const shadowRoot = this.attachShadow({
mode: "open",
slotAssignment: "manual",
});
this.shadowRoot.innerHTML = `<div></div>`;
}
set template(tmpl) {
this.#tmpl = tmpl;
this.#rerender();
}
get template() {
return this.#tmpl;
}
set values(v) {
this.#values = v;
this.#rerender();
}
get values() {
return this.#values;
}
#rerender() {
if (!this.#tmpl || !this.#values) {
return;
}
const container = this.shadowRoot.querySelector("div");
const slots = [];
// Remove all the slots
while (container.firstChild) {
container.firstChild.remove();
}
// Remove all the existing children
while (this.firstChild) {
this.firstChild.remove();
}
// Render all the slots
for (let i = 0; i < this.#values.length; i++) {
const slot = document.createElement("slot");
slots.push(slot);
container.appendChild(slot);
}
// Render all the scoped slotted content.
for (let i = 0; i < this.#values.length; i++) {
const tmpElm = document.createElement("template");
tmpElm.innerHTML = this.#tmpl(this.#values[i]);
this.appendChild(tmpElm.content);
slots[i].assign(this.lastChild);
}
}
}
);
const list = document.querySelector("x-list");
list.template = (item) => {
return `<div>${item.id} - ${item.name}</div>`;
};
list.values = [
{
id: 1,
name: "Buy groceries",
},
{
id: 2,
name: "Clean up my desk",
},
{
id: 3,
name: "Do the laundry",
},
];
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Scoped slot with shadow allocation</title>
</head>
<body>
<x-list></x-list>
<script>
customElements.define(
"x-list",
class extends HTMLElement {
#values = [];
#tmpl;
constructor() {
super();
const shadowRoot = this.attachShadow({
mode: "open",
});
this.shadowRoot.innerHTML = `<div></div>`;
}
set template(tmpl) {
this.#tmpl = tmpl;
this.#rerender();
}
get template() {
return this.#tmpl;
}
set values(v) {
this.#values = v;
this.#rerender();
}
get values() {
return this.#values;
}
#rerender() {
if (!this.#tmpl || !this.#values) {
return;
}
const container = this.shadowRoot.querySelector("div");
// Remove all the existing children
while (this.firstChild) {
this.firstChild.remove();
}
// Render all the scoped slotted content.
for (let i = 0; i < this.#values.length; i++) {
const tmpElm = document.createElement("template");
tmpElm.innerHTML = this.#tmpl(this.#values[i]);
container.appendChild(tmpElm.content);
}
}
}
);
const list = document.querySelector("x-list");
list.template = (item) => {
return `<div>${item.id} - ${item.name}</div>`;
};
list.values = [
{
id: 1,
name: "Buy groceries",
},
{
id: 2,
name: "Clean up my desk",
},
{
id: 3,
name: "Do the laundry",
},
];
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment