Created
November 7, 2023 13:22
-
-
Save akool/a758f23716cf9fdc73ba5331c5c6a9f5 to your computer and use it in GitHub Desktop.
Web component of a table with customizable number of cells
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Document</title> | |
| </head> | |
| <body> | |
| <custom-table tabindex="0"> | |
| <style> | |
| :host { | |
| display: flex; | |
| position: relative; | |
| --table-padding: 1.6rem; | |
| } | |
| #table-container { | |
| position: relative; | |
| padding: var(--table-padding); | |
| } | |
| .custom-table__button { | |
| width: calc(var(--table-padding) - 0.4rem); | |
| height: calc(var(--table-padding) - 0.4rem); | |
| box-sizing: border-box; | |
| padding: 0; | |
| line-height: 1; | |
| } | |
| #add-row-btn, | |
| #remove-row-btn { | |
| position: absolute; | |
| bottom: calc(var(--table-padding) + 0.2rem); | |
| } | |
| #add-row-btn { | |
| left: 0.2rem; | |
| } | |
| #remove-row-btn { | |
| right: 0.2rem; | |
| } | |
| #add-column-btn, | |
| #remove-column-btn { | |
| position: absolute; | |
| right: calc(var(--table-padding) + 0.2rem); | |
| } | |
| #add-column-btn { | |
| top: 0.2rem; | |
| } | |
| #remove-column-btn { | |
| bottom: 0.2rem; | |
| } | |
| td { | |
| border: 1px solid lightgrey; | |
| min-width: 1em; | |
| min-height: 1em; | |
| padding: 0.1em 0.2em; | |
| } | |
| td:empty::after { | |
| content: '\0000a0'; /* non-breaking space */ | |
| visibility: hidden; | |
| } | |
| </style> | |
| <div id="table-container"> | |
| <button class="custom-table__button" id="add-row-btn" type="button" title="Add Row">+</button> | |
| <button class="custom-table__button" id="remove-row-btn" type="button" title="Remove Row">-</button> | |
| <table> | |
| <tbody id="table-body"> | |
| </tbody> | |
| </table> | |
| <button class="custom-table__button" id="add-column-btn" type="button" title="Add Column">+</button> | |
| <button class="custom-table__button" id="remove-column-btn" type="button" title="Remove Column">-</button> | |
| </div> | |
| </custom-table> | |
| <script> | |
| class CustomTable extends HTMLElement { | |
| constructor() { | |
| super(); | |
| this.attachShadow({ mode: 'open' }); | |
| this.shadowRoot.innerHTML = this.innerHTML; | |
| this.tableBody = this.shadowRoot.getElementById('table-body'); | |
| this.addRowBtn = this.shadowRoot.getElementById('add-row-btn'); | |
| this.removeRowBtn = this.shadowRoot.getElementById('remove-row-btn'); | |
| this.addColumnBtn = this.shadowRoot.getElementById('add-column-btn'); | |
| this.removeColumnBtn = this.shadowRoot.getElementById('remove-column-btn'); | |
| this.addRowBtn.addEventListener('click', () => this.addRow()); | |
| this.removeRowBtn.addEventListener('click', () => this.removeRow()); | |
| this.addColumnBtn.addEventListener('click', () => this.addColumn()); | |
| this.removeColumnBtn.addEventListener('click', () => this.removeColumn()); | |
| this.addEventListener('focusin', () => this.setEditable(true)); | |
| this.addEventListener('focusout', () => this.setEditable(false)); | |
| // Initialize table with two rows and two columns | |
| this.addRow(); | |
| this.addRow(); | |
| this.addColumn(); | |
| this.addColumn(); | |
| } | |
| createCell() { | |
| const cell = document.createElement('td'); | |
| return cell; | |
| } | |
| setEditable(editable) { | |
| this.tableBody.querySelectorAll('td').forEach(cell => { | |
| cell.contentEditable = editable ? 'true' : 'false'; | |
| }); | |
| } | |
| addRow() { | |
| const row = document.createElement('tr'); | |
| const columnCount = this.tableBody.querySelector('tr') ? this.tableBody.querySelector('tr').children.length : 0; | |
| for (let i = 0; i < columnCount; i++) { | |
| row.appendChild(this.createCell()); | |
| } | |
| this.tableBody.appendChild(row); | |
| } | |
| removeRow() { | |
| if (this.tableBody.children.length > 1) { | |
| this.tableBody.removeChild(this.tableBody.lastChild); | |
| } | |
| } | |
| addColumn() { | |
| this.tableBody.querySelectorAll('tr').forEach(row => { | |
| row.appendChild(this.createCell()); | |
| }); | |
| } | |
| removeColumn() { | |
| if (this.tableBody.querySelector('tr') && this.tableBody.querySelector('tr').children.length > 1) { | |
| this.tableBody.querySelectorAll('tr').forEach(row => { | |
| row.removeChild(row.lastChild); | |
| }); | |
| } | |
| } | |
| } | |
| customElements.define('custom-table', CustomTable); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment