Enhancement

DataTable

Sorting, filtering and pagination for an existing table

Import
@parallelogram-js/core/components/DataTable
Selector
[data-datatable]
Stylesheet
@parallelogram-js/core/styles/datatable.css

Playground

Bookings

Guest Date Party Spend
Ada Lovelace2 October4$320
Grace Hopper28 September2$140
Katherine Johnson11 October6$1,210
Alan Turing30 September3$265
Hedy Lamarr5 October2$98
Tim Berners-Lee19 October8$1,480
<table data-datatable data-datatable-filterable data-datatable-paginate="4">
  <thead>
    <tr>
      <th data-sort="name">Guest</th>
      <th data-sort="date" data-sort-type="date">Date</th>
      <th data-sort="party" data-sort-type="number">Party</th>
      <th data-sort="spend" data-sort-type="number">Spend</th>
    </tr>
  </thead>
  <tbody>
    <tr><td>Ada Lovelace</td><td data-sort-value="2026-10-02">2 October</td><td>4</td><td>$320</td></tr>
    <tr><td>Grace Hopper</td><td data-sort-value="2026-09-28">28 September</td><td>2</td><td>$140</td></tr>
    <tr><td>Katherine Johnson</td><td data-sort-value="2026-10-11">11 October</td><td>6</td><td>$1,210</td></tr>
    <tr><td>Alan Turing</td><td data-sort-value="2026-09-30">30 September</td><td>3</td><td>$265</td></tr>
    <tr><td>Hedy Lamarr</td><td data-sort-value="2026-10-05">5 October</td><td>2</td><td>$98</td></tr>
    <tr><td>Tim Berners-Lee</td><td data-sort-value="2026-10-19">19 October</td><td>8</td><td>$1,480</td></tr>
  </tbody>
</table>

About

Sortable headers get a button and aria-sort, following the WAI-ARIA sortable table example. Values are read once when the table mounts: numbers are the first number in the cell, ignoring currency symbols, units and group separators, using the decimal separator of the table's lang, and negative after a minus sign or inside parentheses, dates are parsed, text is compared in natural order ("Item 2" before "Item 10"), and blank values always sort last.

Filtering keeps the current sort, pagination is a labelled navigation region with a window of page numbers, hidden while every row fits on one page, and a status message announces which rows are showing after each change. The pagination and status text can be translated through attributes. The original rows are moved rather than copied, and unmounting puts the table back as it was.

Usage

Register the component and the framework loads it the first time a page contains [data-datatable].

import { Parallelogram } from '@parallelogram-js/core';

const app = Parallelogram.create();
app.components.add('[data-datatable]', () => import('@parallelogram-js/core/components/DataTable'));
app.run();

The framework is optional. DataTable.enhanceAll() mounts the component on every matching element by itself, for a page that wants one enhancement rather than a framework:

import DataTable from '@parallelogram-js/core/components/DataTable';

DataTable.enhanceAll();

It takes a selector and the component's options, and returns the instance it mounted them with. What it leaves out is what the framework adds: loading a component only on the pages that use it, mounting again after a page swap, and ordering with dependsOn.

Its styles come from the package stylesheet:

@import '@parallelogram-js/core/styles/datatable.css';

Attributes

NameTypeDefaultDescription
data-datatableflagnoneMarks the table
data-datatable-sortablebooleantrueSort by the headers marked data-sort For every instance, DataTable.defaults.sortable.
data-datatable-filterablebooleanfalseAdd a search box above the table For every instance, DataTable.defaults.filterable.
data-datatable-paginatestringnoneA page size such as 10, or true to use data-datatable-page-size
data-datatable-page-sizenumber10Rows per page For every instance, DataTable.defaults.pageSize.
data-datatable-search-delaynumber300Milliseconds to wait after typing before filtering For every instance, DataTable.defaults.searchDelay.
data-datatable-search-labelstringSearchThe search box's label For every instance, DataTable.defaults.searchLabel.
data-datatable-search-placeholderstringSearch table…The search box's placeholder For every instance, DataTable.defaults.searchPlaceholder.
data-datatable-empty-messagestringNo matching rowsThe row shown when nothing matches For every instance, DataTable.defaults.emptyMessage.
data-datatable-status-messagestringShowing {from}–{to} of {total} rows{sort}The status shown and announced after each change, with {from}, {to}, {total} and {sort} For every instance, DataTable.defaults.statusMessage.
data-datatable-sort-statusstring, sorted by {column}, {direction}The {sort} part of the status while a column is sorted, with {column} and {direction}; without it the status reads the same before and after a sort For every instance, DataTable.defaults.sortStatus.
data-datatable-sort-ascendingstringascendingThe {direction} of an ascending sort For every instance, DataTable.defaults.sortAscending.
data-datatable-sort-descendingstringdescendingThe {direction} of a descending sort For every instance, DataTable.defaults.sortDescending.
data-datatable-pagination-labelstringTable paginationThe pagination region's label For every instance, DataTable.defaults.paginationLabel.
data-datatable-previous-textstringPreviousThe previous page button's text For every instance, DataTable.defaults.previousText.
data-datatable-previous-labelstringPrevious pageThe previous page button's label For every instance, DataTable.defaults.previousLabel.
data-datatable-next-textstringNextThe next page button's text For every instance, DataTable.defaults.nextText.
data-datatable-next-labelstringNext pageThe next page button's label For every instance, DataTable.defaults.nextLabel.
data-datatable-page-labelstringPage {page}Each page number button's label, with {page} For every instance, DataTable.defaults.pageLabel.
data-sortstringnoneMakes the column sortable, naming its key On a header.
data-sort-typestring | number | datestringHow the column compares On a header.
data-sort-valuestringnoneThe value to sort by instead of its text On a cell.
data-datatable-stateset by the componentmounted | loading | loaded | empty | errornoneThe table state
data-datatable-error-messageset by the componentstringnoneWhy the last loadData() failed

Methods

NameSignatureDescription
loadData(element: HTMLTableElement, url: string, rowMapper: (item: unknown) => HTMLTableRowElement) => Promise<void>Replace the rows with rows made from a JSON array fetched from a URL, one row per item
sort(element: HTMLTableElement, column: string, direction?: 'asc' | 'desc') => voidSort by the column with this data-sort key, ascending unless 'desc' is given
filter(element: HTMLTableElement, searchTerm: string) => voidShow only the rows containing the text, and put it in the search box
goToPage(element: HTMLTableElement, page: number) => voidShow a page, when the table paginates and the page exists
clearError(element: HTMLTableElement) => voidClear a loadData() error and show the rows again

Events

NameDetailDescription
datatable:mounted{ config: object }The table was set up DOM event and event bus
datatable:rendered{ totalRows: number; filteredRows: number; displayedRows: number }The visible rows changed DOM event and event bus
datatable:loaded{ url: string; rowCount: number }loadData() finished with rows DOM event and event bus
datatable:empty{ url: string; rowCount: number }loadData() finished without rows DOM event and event bus
datatable:error{ error: Error; url: string; message: string }loadData() failed DOM event and event bus

CSS custom properties

NameDefaultDescription
--datatable-error-defaultvar(--color-danger-text)The load error colour used when neither --datatable-error-color nor --brand-danger is set
--datatable-border-colornoneBorders of the search box and pagination buttons; by default the search box uses --surface-control-border-color and the buttons --color-border-strong
--datatable-button-bgtransparentPagination button background
--datatable-button-colorinheritPagination button text
--datatable-button-hover-bgvar(--color-hover)Pagination button background on hover: the hover tint
--datatable-button-hover-border-colorvar(--color-border-strong)Pagination button border on hover: the strong border colour
--datatable-current-bgvar(--color-accent-hover)The current page button: the stronger accent
--datatable-current-colorvar(--color-accent-contrast)The current page text: the text colour on the accent
--datatable-error-color#b91c1cLoad error message text: a darker red on light pages, and --brand-danger or --color-danger on dark pages
--datatable-header-hover-bgvar(--color-hover)Sortable header background on hover: the hover tint
--datatable-muted-colorvar(--color-text-muted)Status, messages and sort icons: the muted text colour