Accessibility plugin demo

A11y Sortable Table

Add sortable behavior to semantic HTML tables without replacing table markup, keyboard behavior, or screen reader-friendly structure.

Quick facts

Built for semantic data tables

Package
a11y-sortable-table
Type
Vanilla JavaScript and TypeScript
Dependencies
None
Best for
Invoices, issues, tasks, and comparison tables

Examples

Choose the setup that matches your table

These focused examples show the same plugin in different configuration styles, from copyable basics to custom sorting and shareable URL state.

Basic setup

A minimal invoices table that imports the built Pages runtime and initializes every table from data-a11y-sortable-table.

Data attributes

Configure default sort, unsort behavior, descending-first types, and empty-value placement directly in HTML.

Custom order

Use customParsers, customSorters, labels, and a visible status element for operational priority sorting.

URL state and filters

Combine sorting with optional hash-state and filter-state helpers for shareable filtered task tables.

Current view summary

Use the optional summary-state helper to explain the current sort and visible row count in one status sentence.

Reset state recovery

Add a reset action that clears sort, filters, hidden rows, and recovery status text for busy tables.

Column visibility

Let users hide optional columns with native checkboxes while the table remains semantic and sortable.

Saved sort view

Persist and restore the last used sort with the optional saved-view helper and session storage.

Live demo

Sort realistic tables

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.

Option 1: th with a button

Author 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>

Option 2: th without a button

Put 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>

Invoices

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.

Invoices
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

Bug tracker

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

Add the package

Import the JavaScript helper and the CSS file from the package output.

npm install a11y-sortable-table

Basic usage

Keep the HTML table real

HTML

<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>

JavaScript

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

Core methods and options

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.

Common options

Use defaultSort, initialDirection, descendingFirstTypes, allowUnsort, and labels for most table behavior.

Custom sorting

Use data-sort-value for formatted values, or provide customParsers and customSorters for domain-specific order.

Responsive wrappers

Use enhanceScrollableTableWrapper(wrapper) to add region semantics only when horizontal overflow is present.

Optional UI helpers

Add current-view summaries, reset recovery, column visibility, or saved sort state through separate subpath imports when a table needs them.

Accessibility behavior

Designed for progressive enhancement

Key Behavior
Tab Moves through sortable header buttons in the table order.
Enter / Space Activates the focused sort button through native button behavior.

Limitations

What the plugin does not do