References

Beginner-friendly references for web development, with live, editable examples.

The HTML aria-sort attribute

ARIA Accessibility
In short

aria-sort marks the <th> of the column or row a table is sorted by, and gives the direction. On that header the value is ascending, descending or other. The attribute reorders nothing, so your script moves the rows and updates it.

Overview

Table and grid headers carry aria-sort to say whether the items are sorted in ascending or descending order. It goes on the header cell of the sorted column or row, and the rest of the table stays unmarked.

Four tokens are valid. The values ascending and descending give the direction, other means a sort algorithm other than those two has been applied, and none, the default, means no defined sort, which also holds when the attribute is missing.

Only the columnheader and rowheader roles support it. A <th> maps to one of those when HTML counts it as a header, and scope can state which. Use it on table or grid headers only, so a plain <td> isn't the place for it.

When a different column becomes sorted, your script moves the attribute to that column's header, with the value that matches the new order, and takes it off the old header.

The attribute has no effect on the actual sort order, and <table> has no built-in sort, so a script reorders the rows. A <button> inside each sortable header gives keyboard users a control to press.

Syntax

<table>
  <tr>
    <th scope="col" aria-sort="ascending"><button>Price</button></th>
  </tr>
</table>

Values

Value
none | ascending | descending | other

Example

Live example
<table style="border-collapse:collapse;width:100%">
  <caption style="text-align:left;padding-bottom:6px">Stock list. Press a column header to sort, and press it again to reverse the order.</caption>
  <thead>
    <tr>
      <th scope="col" aria-sort="ascending" style="text-align:left"><button type="button">Item <span aria-hidden="true"></span></button></th>
      <th scope="col" style="text-align:left"><button type="button">Price <span aria-hidden="true"></span></button></th>
      <th scope="col" style="text-align:left"><button type="button">Stock <span aria-hidden="true"></span></button></th>
    </tr>
  </thead>
  <tbody id="rows">
    <tr><td>Eraser</td><td>$2</td><td>40</td></tr>
    <tr><td>Notebook</td><td>$5</td><td>12</td></tr>
    <tr><td>Pen</td><td>$3</td><td>75</td></tr>
    <tr><td>Stapler</td><td>$11</td><td>6</td></tr>
  </tbody>
</table>
<p role="status" id="state" style="margin:8px 0 0">Sorted by Item, ascending.</p>
<script>
const headers = [...document.querySelectorAll('thead th')];
const body = document.getElementById('rows');
function drawArrows() {
  headers.forEach(function (th) {
    const order = th.getAttribute('aria-sort');
    th.querySelector('span').innerHTML = order === 'ascending' ? '&#9650;' : order === 'descending' ? '&#9660;' : '';
  });
}
headers.forEach(function (th, column) {
  th.querySelector('button').addEventListener('click', function () {
    const order = th.getAttribute('aria-sort') === 'ascending' ? 'descending' : 'ascending';
    const rows = [...body.rows].sort(function (a, b) {
      const result = a.cells[column].textContent.localeCompare(b.cells[column].textContent, undefined, { numeric: true });
      return order === 'ascending' ? result : -result;
    });
    rows.forEach(function (row) { body.append(row); });
    headers.forEach(function (other) { other.removeAttribute('aria-sort'); });
    th.setAttribute('aria-sort', order);
    drawArrows();
    document.getElementById('state').textContent = 'Sorted by ' + this.firstChild.textContent.trim() + ', ' + order + '.';
  });
});
drawArrows();
</script>

Best practices

  • Draw the sort arrow from aria-sort itself. A selector such as th[aria-sort="ascending"] works, and so does a script that reads the attribute.
  • Leave a header without a button if its column can't be sorted.
  • Explain the sorting in the <caption>, for people who may not see the arrows.
  • Keep other for an order that is neither direction. The value says only that a different sort algorithm was applied, so add visible text that explains which one.

Frequently asked questions

How does aria-sort show which column a table is sorted by?
A header with aria-sort set to ascending, descending or other is the one the table is sorted by. The value says how, and none means no defined sort.
How do I show a sort on two columns with aria-sort?
The aria-sort attribute has no two-column form, and only one header per table or grid should carry it. A table sorted on two keys should therefore still mark only one header.
Is aria-sort=none needed on unsorted headers?
No, unsorted headers don't need aria-sort set to none, because none is the default. The attribute belongs only on the currently sorted column or row.
Can a sort button carry aria-sort instead of its th?
No, aria-sort stays on the th, because header roles support it and the button role doesn't. The button is there to trigger your sort.
Which does the sorting, aria-sort or my script?
Your script does the sorting, since aria-sort moves no rows. Reorder them first, then set the value to match the result.