How can I define a web component that works like <img>
in that it accepts no child elements?
<script>
const QA = (q, d) => Array.prototype.slice.call((d||document).querySelectorAll(q), 0);
const QS = (q, d) => (d||document).querySelector(q);
</script>
<template id="push-message">
<style>
message { display: grid; font-family: sans-serif; background: #eee; outline: 1px solid; }
.badge { }
</style>
<message>
<img class="badge">
<img class="icon">
<img class="image">
</message>
</template>
<script>
const wpm = 'push-message';
customElements.define(wpm,
class extends HTMLElement {
constructor() {
super();
const l = QS(`#${wpm}`).content.cloneNode(true);
const s = this.attachShadow({ mode: 'open' }); s.appendChild(l);
}
QS(q) { return QS(q, this.shadowRoot); }
QA(q) { return QA(q, this.shadowRoot); }
static get observedAttributes() { return [ "badge", "icon", "image" ]; }
attributeChangedCallback(a, o, n) {
if (/^(badge|icon|image)$/.test(a))
this.QS(`.${a}`).src = n;
}
});
</script>
<push-message
badge="//google.com/favicon.ico"
icon="//google.com/favicon.ico"
image="//google.com/favicon.ico">
<p>ok</p>
DOM
should be
<push-message></push-message>
<p></p>
not
<push-message><p></p></push-message>
and ok
should display in the result.
Is there a way to change customElements.define
to avoid having to explicitly close <push-message></push-message>
and just use <push-message>
but have it implicitly self-close?
Autonomous Custom Elements require a closing tag: Do custom elements require a close tag?
You can create a Customized Built-In Element extended from HTMLImageElement
to get a a self-closing IMG tag:
<img is="push-message" badge="//google.com/favicon.ico">
<img is="push-message" icon="//google.com/favicon.ico">
<img is="push-message" image="//google.com/favicon.ico">
<p>ok</p>
But an IMG can only have one src, so you might as well create 3 elements and use
<img is="message-badge">
<img is="message-icon">
<img is="message-image">