Basic setup
A minimal invoices table that imports the built Pages runtime and
initializes every table from data-a11y-sortable-table.
Accessibility plugin demo
Add sortable behavior to semantic HTML tables without replacing table markup, keyboard behavior, or screen reader-friendly structure.
Quick facts
a11y-sortable-tableExamples
These focused examples show the same plugin in different configuration styles, from copyable basics to custom sorting and shareable URL state.
A minimal invoices table that imports the built Pages runtime and
initializes every table from data-a11y-sortable-table.
Configure default sort, unsort behavior, descending-first types, and empty-value placement directly in HTML.
Use customParsers, customSorters, labels,
and a visible status element for operational priority sorting.
Combine sorting with optional hash-state and filter-state helpers for shareable filtered task tables.
Use the optional summary-state helper to explain the current sort and visible row count in one status sentence.
Add a reset action that clears sort, filters, hidden rows, and recovery status text for busy tables.
Let users hide optional columns with native checkboxes while the table remains semantic and sortable.
Persist and restore the last used sort with the optional saved-view helper and session storage.
Live demo
Use Tab to reach a column header button. Press Enter or Space to sort, then confirm focus stays on the same button and the status message updates.
th with a buttonAuthor the native button yourself when you want full control over the label, classes, and icon markup.
<th scope="col">
<button
class="a11y-sortable-table__button"
type="button"
data-sort-key="amount"
data-sort-type="number"
>
Amount
<span class="a11y-sortable-table__icon" aria-hidden="true"></span>
</button>
</th>
th without a buttonPut sorting data on the header cell and the plugin will generate the button during progressive enhancement.
<th
scope="col"
data-sort-key="amount"
data-sort-type="number"
data-align="end"
>
Amount
</th>
This table starts sorted by date descending. Amount and date columns use machine-readable sort values while keeping human-readable text.
Scroll horizontally to view all columns.
| INV-1001 | Acme Corp | 30 May 2026 | €199.99 | Paid |
| INV-1002 | Globex Inc | 18 Apr 2026 | €89.50 | Pending |
| INV-1003 | Initech | 5 Mar 2026 | €450.00 | Overdue |
| INV-1004 | Umbrella Ltd | 14 Feb 2026 | €1,200.00 | Paid |
| INV-1005 | Acme Corp | 20 Jan 2026 | €75.00 | Pending |
| INV-1006 | Cyberdyne Systems | 1 Dec 2025 | €3,200.00 | Paid |
| INV-1007 | Soylent Corp | 15 Nov 2025 | €640.00 | Overdue |
| INV-1008 | Initech | 28 Oct 2025 | €320.50 | Paid |
The priority column uses a custom parser so Critical, High, Medium, and Low sort in product-priority order instead of alphabetically.
Scroll horizontally to view all columns.
| BUG-042 | Login button unresponsive on iOS Safari | Critical | 28 May 2026 |
| BUG-041 | Table header overlap during print | Low | 22 May 2026 |
| BUG-040 | Avatar upload fails for PNG over 2 MB | High | 10 May 2026 |
| BUG-039 | Pagination breaks on search filter | Medium | 30 Apr 2026 |
| BUG-038 | Dark mode flicker on page load | Low | 15 Apr 2026 |
Install
Import the JavaScript helper and the CSS file from the package output.
npm install a11y-sortable-table
Basic usage
<table class="a11y-sortable-table" data-a11y-sortable-table>
<caption>Invoices</caption>
<thead>
<tr>
<th scope="col">
<button
class="a11y-sortable-table__button"
type="button"
data-sort-key="amount"
data-sort-type="number"
>
Amount
<span class="a11y-sortable-table__icon" aria-hidden="true"></span>
</button>
</th>
</tr>
</thead>
<tbody>
<tr>
<td data-sort-value="199.99">$199.99</td>
</tr>
</tbody>
</table>
import { createSortableTable } from "a11y-sortable-table";
import "a11y-sortable-table/styles.css";
const table = document.querySelector("[data-a11y-sortable-table]");
if (table instanceof HTMLTableElement) {
createSortableTable(table, {
defaultSort: { key: "amount", direction: "descending" },
allowUnsort: true
});
}
API
| API | Purpose |
|---|---|
createSortableTable(table, options) |
Initializes one semantic table and returns an instance. |
initSortableTables(options, root) |
Initializes every matching table in a page or fragment. |
sortBy(key, direction, config) |
Sorts a column or restores original order with "none". |
clearSort(), refresh(), destroy() |
Manage current sort state, refreshed rows, and lifecycle cleanup. |
syncSortableTableHashState() |
Opt-in URL hash synchronization from the /hash-state subpath. |
syncSortableTableFilterState() |
Optional hash-driven row visibility integration from the /filter-state subpath. |
syncSortableTableSummaryState() |
Optional current-view summary text from the /summary-state subpath. |
createSortableTableReset() |
Optional reset button/controller behavior from the /reset-state subpath. |
createSortableTableColumnVisibility() |
Optional checkbox-driven column visibility from the /column-visibility subpath. |
syncSortableTableSavedView() |
Optional last-sort persistence from the /saved-view subpath. |
Use defaultSort, initialDirection,
descendingFirstTypes, allowUnsort, and
labels for most table behavior.
Use data-sort-value for formatted values, or provide
customParsers and customSorters for
domain-specific order.
Use enhanceScrollableTableWrapper(wrapper) to add region
semantics only when horizontal overflow is present.
Add current-view summaries, reset recovery, column visibility, or saved sort state through separate subpath imports when a table needs them.
Accessibility behavior
aria-sort.hidden attribute.| Key | Behavior |
|---|---|
| Tab | Moves through sortable header buttons in the table order. |
| Enter / Space | Activates the focused sort button through native button behavior. |
Limitations
th[data-sort-key] cells.