The HTML aria-sort attribute
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
<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' ? '▲' : order === 'descending' ? '▼' : '';
});
}
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-sortitself. A selector such asth[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
otherfor 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.























