Skip to content

Sortable Data Table

Tailwind CSS data table with clickable column headers that sort text, dates and numbers, with aria-sort, arrow indicators and a responsive scroll wrapper.

Tailwind CSS Tables Responsive #accessible #data #responsive #sort #table

Live preview

Open in new tab

Code

A sortable data table built with Tailwind CSS and a dependency-free JavaScript sorter. Clicking a column header sorts the rows by text, date or number, a second click reverses the order, and arrow icons plus aria-sort show the current state. It suits order lists, admin dashboards and reports.

How it works

The root is .tst-table. The table sits inside a horizontally scrollable wrapper (overflow-x-auto with min-w-[640px] on the table), so on phones the table scrolls instead of squeezing columns. Each th carries data-tst-type (text, date or number) and an aria-sort attribute, and contains a full-width .tst-sort button with a two-part .tst-arrow SVG.

On DOMContentLoaded the script initializes every .tst-table. A click on a header button reads its current aria-sort and toggles between ascending and descending; an unsorted number column starts descending (largest first), other types start ascending. The sortBy() function reads each row's cell value, preferring a data-tst-value attribute over the visible text, so formatted values like $12,980.00 or Oct 3, 2026 sort correctly. Text is compared with Intl.Collator, and the original row position breaks ties so the sort stays stable. Rows are moved back into the tbody in one DocumentFragment, all other headers are reset to aria-sort="none", and a short tst-flash highlight plays on the rows. Any header that starts with aria-sort="ascending" or "descending" in the markup is applied as the initial sort.

style.css dims the inactive arrow half (.tst-up / .tst-down) and darkens the sorted header.

Customization

  • data-tst-type on a th: set number, date or text to control how that column is compared.
  • data-tst-value on a td: provide a raw sort value (ISO date, plain number) when the displayed text is formatted.
  • aria-sort="descending" on the Date header: move it to another th to change the initial sort, or set all to none to keep the source order.
  • Remove the .tst-sort button and the aria-sort attribute from a th (keep plain text) to make that column non-sortable.
  • bg-violet-600 on thead and bg-violet-50 on .tst-table: swap violet for another Tailwind color to retheme.
  • min-w-[640px] on the table: lower it if your columns are narrow, raise it for wide data.
  • The status.textContent line in sortBy(): change or translate the announcement text.

Accessibility

Headers use scope="col", and the sort controls are real buttons inside the th, so they are reachable with Tab and activated with Enter or Space. aria-sort is kept up to date on every header, which screen readers announce when entering a column. A role="status" region reports each change, for example "Sorted by Amount, descending.". The scroll wrapper is a focusable role="region" labelled by the table heading, so keyboard users can scroll it. Header buttons show a white inset focus outline, arrows are aria-hidden, and the highlight and arrow transitions are disabled under prefers-reduced-motion.

Usage notes

The sorter works on the rows in the DOM, so it is best for up to a few hundred rows. For paged or server-side data, call your API from the click handler instead.

Requirements

Add these to your page (already included in the download):

  • <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>

The Tailwind browser build is for prototyping. In production, compile Tailwind with its CLI or your bundler.

Sortable Data Table – Tailwind CSS tables component screenshot
Sortable Data Table · Tailwind CSS Tables

More Tables

Table with Sticky Header – Pure CSS tables preview

Table with Sticky Header

Dark striped data table in pure CSS with a sticky header row and sticky first column inside a scrollable, keyboard-focusable container.

Table with Search Filter – Bootstrap 5 tables preview

Table with Search Filter

Bootstrap 5 team directory table with live search, status filter, highlighted matches, result counter and empty state.

Responsive Table with Actions – Bootstrap 5 tables preview

Responsive Table with Actions

Responsive Bootstrap 5 invoice table with status badges, a status filter and row action dropdowns to mark as paid, remind or delete.