В идеале должен быть shadowRoot со слотом для html элемента, иначе можно вставить таблицу в shadowRoot. Этот пример будет нацелен на HTML через слот:
в HTML (статическая страница или что-то еще), включая: <data-grid>data-grid</data-grid>
в загруженном модуле, через импорт или скрипт type = module:
/*
this is an example to show basics, it's not ideal, however it answers the question with a working example
*/
class DataTable extends HTMLElement {
constructor() {
super();
// static, or request, or setup default and update later...
this.dataList = [[1,2], [7,9]];
this.dataHeaders = ['one', 'two'];
// only work with shadowRoot in constructor, never the HTML element
// minimize work here too, do that later in lifecycle callbacks
this.attachShadow({mode:'open'}).innerHTML = `
<!-- NOTE how this th styling doesn't work because the table is rendered into the HTML, not the shadowRoot -->
<style>
/* styles shadow content in the host */
:host th{text-align:left;color:blue;}
/* only top-level selectors */
::slotted(table){text-align:right;}
</style>
<table style="width:100%;"><tr><th>ok</th></tr></table>
<button>update table</button>
<slot></slot>
`;
this.shadowRoot.querySelector('button').addEventListener('click', this.updateTable.bind(this));
}
connectedCallback(){
// change attributes, html, etc here
this.createTable();
}
random(){
const max=Date.now();
return Math.floor(Math.random() * Math.floor(max));
}
updateTable(){
this.dataList = this.dataList.map((row, i)=>{
return row.map(this.random);
});
this.createTable();
}
createTable() {
// use the render cycle
cancelAnimationFrame(this._createTable);
this._createTable = requestAnimationFrame(()=>{
// html will go into the shadowRoot slot (default or whatever is targeted)
this.innerHTML = `
<table>
<thead><tr>
${ this.dataHeaders.reduce((html, col, i)=>{
return html + `<th>${i+1} ${col}</th>`;
}, '') }
</tr></thead>
<tbody>
<tr>${ this.dataList.map((row, i)=>{
return `<td>${ row.join('</td><td>') }</td>`;
}).join('</tr><tr>') }</tr>
</tbody>
</table>
`;
});
}
}
// define the element, if not already
customElements.get('data-grid') || customElements.define('data-grid', DataTable);
См. Рабочий пример ( commit ) и документы Google Web Developer для рекомендации по веб-компонентам .