Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
light dom render custom element
// adapted from example https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_templates_and_slots
document.body.insertAdjacentHTML(
'beforeend',
`
<template id="element-details-template">
<style>
details {font-family: "Open Sans Light",Helvetica,Arial}
.name {font-weight: bold; color: #217ac0; font-size: 120%}
h4 { margin: 10px 0 -8px 0; }
h4 span { background: #217ac0; padding: 2px 6px 2px 6px }
h4 span { border: 1px solid #cee9f9; border-radius: 4px }
h4 span { color: white }
.attributes { margin-left: 22px; font-size: 90% }
.attributes p { margin-left: 16px; font-style: italic }
</style>
<slot name="omg"><i>multiple</i><b>nodes</b></slot>
<details>
<summary>
<span>
<code class="name">&lt;<slot name="element-name">NEED NAME</slot>&gt;</code>
<i class="desc"><slot name="description">NEED DESCRIPTION</slot></i>
</span>
</summary>
<div class="attributes">
<h4><span>Attributes</span></h4>
<slot name="attributes"><p>None</p></slot>
</div>
</details>
<hr>
</template>`
);
customElements.define(
'element-details',
class extends HTMLElement {
constructor() {
super();
}
renderLight() {
const templateId = `${this.localName}-template`;
const template = document.getElementById(templateId).content;
const content = template.cloneNode(true);
const style = content.querySelector('style');
if (style) style.parentNode.removeChild(style);
if (style && !document.querySelector(`#${this.localName}-style`)) {
style.id = `${this.localName}-style`;
document.body.insertAdjacentElement('afterbegin', style);
}
const defaultSlot = content.querySelector('slot:not([name])');
if (defaultSlot) {
const fragment = document.createDocumentFragment();
while (this.firstChild) {
fragment.appendChild(this.firstChild);
}
this.appendChild(content);
return;
}
const slots = content.querySelectorAll('slot[name]');
slots.forEach((slot) => {
const el = this.querySelector(`[slot="${slot.name}"]`);
const parent = slot.parentNode;
if (el) return parent.replaceChild(el, slot);
// handle missing slots with default content
const fragment = document.createDocumentFragment();
while (slot.firstChild) {
fragment.appendChild(slot.firstChild);
}
parent.replaceChild(fragment, slot);
});
this.appendChild(content);
}
renderShadow() {
const templateId = `${this.localName}-template`;
var template = document.getElementById(templateId).content;
this.attachShadow({ mode: 'open' }).appendChild(template.cloneNode(true));
}
connectedCallback() {
if (this.hasAttribute('light')) return this.renderLight();
this.renderShadow();
}
}
);
document.body.insertAdjacentHTML(
'beforeend',
`
<element-details light>
<span slot="omg">test a top-level slot</span>
<span slot="element-name">slot</span>
<span slot="description">A placeholder inside a web
component that users can fill with their own markup,
with the effect of composing different DOM trees
together.</span>
<dl slot="attributes">
<dt>name</dt>
<dd>The name of the slot.</dd>
</dl>
</element-details>`
);
// make sure we only inject the style once
document.body.insertAdjacentHTML(
'beforeend',
`
<element-details light>
<span slot="element-name">template (light)</span>
<span slot="description">A mechanism for holding client-
side content that is not to be rendered when a page is
loaded but may subsequently be instantiated during
runtime using JavaScript.</span>
</element-details> `
);
document.body.insertAdjacentHTML(
'beforeend',
`
<element-details>
<span slot="element-name">template (shadow)</span>
<span slot="description">A mechanism for holding client-
side content that is not to be rendered when a page is
loaded but may subsequently be instantiated during
runtime using JavaScript.</span>
</element-details>`
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.