class Table extends HTMLElement {
// attributes
constructor() {
super();
this.name = 'undefined';
this.icon = 'bi-patch-question';
}
// component attributes
static get observedAttributes() {
return ['name', 'icon', 'properties'];
}
// attribute change
attributeChangedCallback(property, oldValue, newValue) {
if (oldValue == newValue) return;
this[ property ] = newValue;
}
connectedCallback() {
const shadow = this.attachShadow({ mode: 'open' });
shadow.innerHTML = `
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css">
<div class="card">
<table class="table">
<tr>
<caption>${this.name}<i class="bi ${this.icon}"></i></caption>
</tr>
<!-- here should be the em-tds -->
</table></div>
<style>
.card {
border: 1px solid lightgray;
border-radius: 15px;
margin: 10px 0;
padding: 15px;
}
table {
width: 100%;
border-collapse: collapse;
}
tr {
border-top: 1px solid lightgrey;
}
tr:first-child {
border: none;
}
td {
width: 100%;
padding: 7px;
font-size: 18px;
vertical-align: middle;
}
caption {
position: relative;
font-family: ExtraBold;
padding: 7px;
margin-bottom: 5px;
text-align: left;
font-size: 18px;
text-decoration: 2px underline;
}
caption i {
position: absolute;
right: 6px;
font-size: 22px;
}
</style>
`
}
}
class TableTds extends HTMLElement {
// attributes
constructor() {
super();
this.name = 'undefined';
this.value = 'undefined';
}
// component attributes
static get observedAttributes() {
return ['name', 'value'];
}
// attribute change
attributeChangedCallback(property, oldValue, newValue) {
if (oldValue == newValue) return;
this[ property ] = newValue;
}
connectedCallback() {
const shadow = this.attachShadow({ mode: 'open' });
shadow.innerHTML = `
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css">
<td>${this.name}</td>
<td>${this.value}></td>
`
}
}
customElements.define('em-table', Table);
customElements.define('em-td', TableTds);
<em-table name="test">
<em-td name="test" value="10"></em-td>
<em-td name="test" value="10"></em-td>
</em-table>
I'm working on new web-components for my plattform and ran in some kind of issue. Creating web-components works fine for me but I wanted to create sub-components inside the tags of a web-component. Obviously that has not worked, because the component is protected from everything else...
In my case its about a table web-component, in which I would like to have the html-tds as subcomponents, to later use them properly.
I've tried to use slots but that has not worked...
This should get you started, you need to add more yourself.
Main point is not to wrap Everything in a shadowDOM,
let your em-td
find their "table", without having to pierce UP through a shadowroot boundary
with:
connectedCallback() {
this.closest("em-table")
.shadowRoot
.querySelector("table")
.append(this.tr);
}
Note: using a declarative shadowDOM <template shadowroot="open">
for em-table
here.
You can move it all to its constructor
if you don't want to start from SSR/HTML
<em-table name="test">
<template shadowroot="open">
<div class="card">
<table class="table">
<caption></caption>
</table>
</div>
<style>
tr{background:pink}
</style>
</template>
<em-td name="test1" value="10"></em-td>
<em-td name="test2" value="20"></em-td>
</em-table>
<script>
customElements.define('em-table', class extends HTMLElement {
caption(name, icon) {
let html = `${name}<i class="bi ${icon}"></i>`;
this.shadowRoot.querySelector("caption").innerHTML = html;
}
connectedCallback() {
this.caption('caption', 'bi-patch-question');
}
static get observedAttributes() {
return ['name', 'icon', 'properties'];
}
attributeChangedCallback(property, oldValue, newValue) {
if (oldValue == newValue) return;
this[property] = newValue;
}
});
customElements.define('em-td', class extends HTMLElement {
static get observedAttributes() {
return ['name', 'value'];
}
constructor() {
super();
this.tr = document.createElement("tr");
this._name = document.createElement("td");
this._value = document.createElement("td");
this.tr.append(this._name, this._value);
}
attributeChangedCallback(property, oldValue, newValue) {
if (oldValue == newValue) return;
this[property] = newValue;
}
set name(v) {
this._name.innerText = v;
}
set value(v) {
this._value.innerText = v;
}
connectedCallback() {
this.closest("em-table")
.shadowRoot.querySelector("table")
.append(this.tr);
}
});
</script>
From the <TR>
documentation on MDN:
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/tr
Permitted parents
<table>
(only if the table has no child<tbody>
element, and even then only after any<caption>
,<colgroup>
, and<thead>
elements); otherwise, the parent must be<thead>
,<tbody>
or<tfoot>
So
<em-table>
<tr>
is not valid HTML