simple-data-table
v1.5.0
Published
๐จ Lightweight and simple data table with no dependencies
Maintainers
Readme
simple-data-table
๐จ Lightweight and simple data table with no dependencies
Preview ๐
https://piecioshka.github.io/simple-data-table/demo/

To run the demo locally (it starts on the first free port from 3000 up):
npm run demoFeatures
- ๐ฆ No dependencies, no build step (a single
<script>tag is enough) - ๐ชถ Tiny package (~4 kB of plain JavaScript)
- ๐ Works as ES module, UMD, CommonJS or AMD module
- ๐ Display any data (array with objects) in simple table layout
- โ๏ธ Edit cells, add and remove rows out of the box
- ๐ Smart sorting (numbers as numbers, ISO dates chronologically, text in natural order, empty values last)
- ๐งฎ Custom comparing function for full control over sorting (
setSortComparingFn()) - ๐ก Custom events for updated cells, added and removed rows and sorting (
on(),emit()) - ๐จ Two skins included (light
default.cssand darkmidnight.css) - ๐๏ธ Support custom skins (style children of
div.simple-data-table) - ๐ Readonly mode (disabled inputs, no add and remove buttons)
- ๐ก๏ธ Your data is never mutated (rows are copied on
load()) - ๐ TypeScript definitions included
- โ๏ธ Fluent API (not available in all public methods)
- โฟ Keyboard accessible (visible focus ring on inputs and buttons)
Usage
Installation:
npm install simple-data-table<link
rel="stylesheet"
href="node_modules/simple-data-table/src/skins/default.css"
/>
<script src="node_modules/simple-data-table/src/index.js"></script>const $container = document.querySelector('#place-to-render');
const options = {/* all available options are described below */};
const t = new SimpleDataTable($container, options);
t.load([
{
column1: 'Cell 1',
column2: 'Cell 2',
column3: 'Cell 3',
},
{
column1: 'Cell 4',
column2: 'Cell 5',
column3: 'Cell 6',
},
{
column1: 'Cell 7',
column2: 'Cell 8',
column3: 'Cell 9',
},
{
column1: 'Cell 10',
column2: 'Cell 11',
column3: 'Cell 12',
},
]);
t.render();ES modules
The package also ships an ES module entry point, so import works with a bundler and in Node:
import { SimpleDataTable } from 'simple-data-table';
// a default export is available too:
// import SimpleDataTable from 'simple-data-table';Straight from a browser, without a bundler, point the import at the file itself:
<script type="module">
import { SimpleDataTable } from './node_modules/simple-data-table/src/index.mjs';
</script>Skins
The package ships two stylesheets:
<!-- light, used by default -->
<link
rel="stylesheet"
href="node_modules/simple-data-table/src/skins/default.css"
/>
<!-- optional dark skin -->
<link
rel="stylesheet"
href="node_modules/simple-data-table/src/skins/midnight.css"
/>The dark skin is opt-in, so it never overrides your own styles. Add the midnight class to the wrapper after rendering:
t.render();
$container.querySelector('.simple-data-table').classList.add('midnight');Options
addButtonLabel (Default: 'โ')
Change the label of the button which adds a new row.
const t = new SimpleDataTable($container, {
addButtonLabel: 'New record'
});
t.load(...);
t.render();defaultColumnPrefix (Default: 'column')
Define the "name" prefix of cells in newly added columns.
const t = new SimpleDataTable($container, {
defaultColumnPrefix: 'random'
});
t.load(...);
t.render();defaultColumnNumber (Default: null)
Define how many columns a new row should contain in an empty table.
By default, the number of headers or the number of cells in the first row of data is used.
const t = new SimpleDataTable($container, {
defaultColumnNumber: 7
});
t.load(...);
t.render();defaultHighlightedCellClass (Default: 'highlighted-cell')
Define class of highlighted cell.
const t = new SimpleDataTable($container, {
defaultHighlightedCellClass: 'my-highlight'
});
t.load(...);
t.render();readonly (Default: false)
Disable editing: inputs are disabled and rows cannot be added or removed.
const t = new SimpleDataTable($container, {
readonly: true
});
t.load(...);
t.render();API
NOTE: Methods which read from the DOM (getRowsCount, findCellsByContent, getCell, highlightCell, clearHighlightedCells, setInputCellContent) require calling render() first.
render(): SimpleDataTable
Render table into DOM.
getRowsCount(): number
Get number of rows.
findCellsByContent( ...content: Array<string> ): Array<{ rowIndex: number, cellIndex: number }>
Get list of cell positions which contains passed strings.
getCell( rowIndex: number, cellIndex: number ): HTMLElement | null
Get DOM reference of concrete cell.
highlightCell( rowIndex: number, cellIndex: number )
Add class to concrete cell.
clearHighlightedCells()
Remove CSS class of all highlighted cells.
setInputCellContent( rowIndex: number, cellIndex: number, content: string )
Put content into input in concrete cell.
setHeaders( items: Array<string> )
Setup column headers. Sorting is enabled by default.
load( data: Array<object> )
Loading data into table component. Rows are copied, so editing cells never mutates the objects passed in.
emit( name: string, payload: any )
Trigger event on SimpleDataTable instance.
on( name: string, handler: Function )
Listen on events.
sortByColumn( columnIndex: number )
Sorts data and triggers DATA_SORTED event.
WARNING: Function sortByColumn() runs render() under the hood.
setSortComparingFn( fn: (val1, val2) => number )
Replace the default comparing function. Empty values are handled before the function is called, so it never receives null, undefined or ''.
SimpleDataTable.compareValues( val1, val2 ): number
Default comparing function, which picks a strategy from the value types:
- numbers (also numeric strings like
'10') are compared numerically, so2comes before10 - ISO dates (
2026-01-05,2026-01-05T12:00:00Z) are compared chronologically - anything else is compared as text with natural ordering, so
item2comes beforeitem10
Empty values (null, undefined, '') always sink to the bottom, regardless of the sort direction.
SimpleDataTable.isEmptyValue( value ): boolean
Checks whether a value is treated as empty by the sorting logic.
Events
SimpleDataTable.EVENTS.UPDATE
Event is dispatching when you change any of input in table.
const t = new SimpleDataTable($container);
t.on(SimpleDataTable.EVENTS.UPDATE, (data) => {
// do some stuff with the updated data...
});SimpleDataTable.EVENTS.ROW_ADDED
Event is dispatching when you add new record.
const t = new SimpleDataTable($container);
t.on(SimpleDataTable.EVENTS.ROW_ADDED, () => {
// do some stuff...
});SimpleDataTable.EVENTS.ROW_REMOVED
Event is dispatching when you remove any record.
const t = new SimpleDataTable($container);
t.on(SimpleDataTable.EVENTS.ROW_REMOVED, () => {
// do some stuff...
});SimpleDataTable.EVENTS.DATA_SORTED
Event is dispatching after data is sorted with sortByColumn function.
const t = new SimpleDataTable($container);
t.on(SimpleDataTable.EVENTS.DATA_SORTED, () => {
// do some stuff...
});Static
SimpleDataTable.clearElement( $element: HTMLElement )
Recursive remove children from passed HTMLElement.
License
The MIT License @ 2026
