A web component that enables users to hide & show columns on an HTML table.
Additional demos:
npm install @aarongustafson/table-modifiableImport the package to automatically define the <table-modifiable> custom element:
import '@aarongustafson/table-modifiable';Or use the define-only script in HTML:
<script src="./node_modules/@aarongustafson/table-modifiable/define.js" type="module"></script>Import the class and define the custom element with your preferred tag name:
import { TableModifiableElement } from '@aarongustafson/table-modifiable/table-modifiable.js';
customElements.define('my-custom-name', TableModifiableElement);You can also call the provided helper to register the element without importing the class:
import { defineTableModifiable } from '@aarongustafson/table-modifiable/define.js';
defineTableModifiable('my-custom-name');<table-modifiable removable="Name,Email,Phone" start-with="Name,Email">
<table>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Phone</th>
</tr>
</thead>
<tbody>
<tr>
<td>John Doe</td>
<td>john@example.com</td>
<td>555-1234</td>
</tr>
</tbody>
</table>
</table-modifiable>| Attribute | Type | Default | Description |
|---|---|---|---|
removable |
string |
"" |
Comma-separated list of all column names that can be shown/hidden |
start-with |
string |
(all removable) | Comma-separated list of which columns should be visible by default. If not specified, all removable columns will be shown initially |
button-label |
string |
"Modify Table" |
Text label for the toggle button |
button-aria-label |
string |
(same as button-label) | Accessible label for the toggle button. Use this to provide a more descriptive label for screen readers if needed |
tools-label |
string |
"Show/Hide Columns" |
Heading text for the popover panel |
All of the attributes above have matching camelCase properties (removable, startWith, buttonLabel, buttonAriaLabel, toolsLabel). Setting a property updates the corresponding attribute and schedules the component to re-render.
const modifiable = document.querySelector('table-modifiable');
modifiable.removable = 'Name,Email';
modifiable.startWith = 'Name';The component fires custom events that you can listen to:
| Event | Description | Detail |
|---|---|---|
table-modifiable:change |
Fired when a column's visibility is toggled | { column: string, visible: boolean } |
const element = document.querySelector('table-modifiable');
element.addEventListener('table-modifiable:change', (event) => {
console.log(`Column "${event.detail.column}" is now ${event.detail.visible ? 'visible' : 'hidden'}`);
});| Property | Default | Description |
|---|---|---|
--table-modifiable-tool-bg |
(none) | Background color for the modification tools popover |
--table-modifiable-tool-color |
(none) | Text color for the modification tools popover |
You can style the generated elements directly to customize the appearance:
/* Style the toggle button */
.modification-tools-toggle {
background: #0969da;
color: white;
border: none;
padding: 0.5rem 1rem;
border-radius: 4px;
font-size: 1rem;
cursor: pointer;
}
.modification-tools-toggle:hover {
background: #0860ca;
}
/* Style the popover */
.modification-tools {
background: var(--table-modifiable-tool-bg, white);
color: var(--table-modifiable-tool-color, #333);
padding: 1rem;
border-radius: 6px;
border: 1px solid #d0d7de;
box-shadow: 0 8px 24px rgba(140, 149, 159, 0.2);
min-width: 250px;
}
.modification-tools-heading {
font-weight: bold;
display: block;
margin-bottom: 0.75rem;
font-size: 1.1rem;
}
.modification-tools ul {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.modification-tools li {
margin: 0;
}
.modification-tools label {
cursor: pointer;
user-select: none;
}This component wraps an HTML table and adds interactive controls to show/hide columns:
-
Place your table inside the component: The component uses Light DOM, so your table remains in the regular DOM and is fully accessible.
-
Specify removable columns: Use the
removableattribute to list which columns can be toggled. The column names must match the text content of the<th>elements in the first header row exactly. -
Set initial visibility: Optionally use
start-withto specify which columns should be visible when the page loads. Any columns inremovablebut not instart-withwill be hidden initially. -
Toggle via popover: The component creates a button that opens a popover with checkboxes. Users can check/uncheck these to show/hide the corresponding columns. The popover uses the native Popover API.
-
Customize labels: Use the
button-label,button-aria-label, andtools-labelattributes to customize the text shown to users.
Note: This component works with simple tables (one header row, matching body cells). It does not support colspan or rowspan attributes.
<table-modifiable removable="Product,Price,Stock,Category" start-with="Product,Price">
<table>
<thead>
<tr>
<th>Product</th>
<th>Price</th>
<th>Stock</th>
<th>Category</th>
</tr>
</thead>
<tbody>
<tr>
<td>Widget</td>
<td>$9.99</td>
<td>42</td>
<td>Tools</td>
</tr>
</tbody>
</table>
</table-modifiable><table-modifiable
removable="Name,Email,Phone,Address"
start-with="Name,Email"
button-label="Customize Columns"
button-aria-label="Customize which columns are visible in the table"
tools-label="Select Visible Columns">
<table>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Phone</th>
<th>Address</th>
</tr>
</thead>
<tbody>
<tr>
<td>Jane Doe</td>
<td>jane@example.com</td>
<td>555-5678</td>
<td>123 Main St</td>
</tr>
</tbody>
</table>
</table-modifiable>This package ships bundled type definitions (table-modifiable.d.ts). You can import the element type, the change event payload, and the registration helper:
import type {
TableModifiableElement,
TableModifiableChangeEvent,
} from '@aarongustafson/table-modifiable/table-modifiable.js';
import { defineTableModifiable } from '@aarongustafson/table-modifiable/define.js';
defineTableModifiable();
const element = document.querySelector('table-modifiable') as TableModifiableElement;
element.addEventListener(
'table-modifiable:change',
(event: TableModifiableChangeEvent) => {
console.log(event.detail.column, event.detail.visible);
},
);This component uses modern web standards:
- Custom Elements v1
- ES Modules
- Popover API
For older browsers, you may need polyfills.
# Install dependencies
npm install
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Lint code
npm run lint
# Format code
npm run format
# View demo
open demo/index.htmlMIT © Aaron Gustafson