Standards · ARIA

Property Widget state

aria-sort

On a column or row header in a sortable grid or table, announces the current sort direction. Values: "ascending", "descending", "other", or "none". Only one header in the table should carry a sorted value at a time.

When to use

On role="columnheader" or role="rowheader" (or a native <th> acting as one) in a grid or table that the user can re-sort. The attribute tells AT both that the column is sortable and which way it is currently sorted, so a screen-reader user hears “Last name, sorted ascending” before reading down the column.

If the column is not sortable, do not put aria-sort on it. The attribute is the contract that says “you can change this”.

How it behaves

Accepts four token values:

  • "ascending" — A→Z, 0→9, oldest→newest.
  • "descending" — Z→A, 9→0, newest→oldest.
  • "none" — sortable, but not currently sorted by this column. This is the default state once another column takes over.
  • "other" — sortable, currently sorted by a non-alphabetic, non-numeric rule that doesn’t fit ascending/descending (a custom relevance score, for example). Rare in practice.

Only one header per table should carry "ascending", "descending", or "other" at a time. When the user changes the sort, set the new column to its new value and reset the previous column to "none" (or remove the attribute).

aria-sort is purely an announcement. The actual sort behaviour — click handler, keyboard activation, the row reordering — is your job. AT does not sort the table for you.

Common failures

  • Updating the visible sort indicator (arrow icon) but forgetting to update aria-sort. Screen-reader users hear the wrong direction.
  • Leaving two columns with aria-sort="ascending" after clicking a new header. The first column is no longer driving the sort but still claims to.
  • Putting aria-sort on a non-sortable column. AT promises sort behaviour the user can’t actually trigger.
  • Using a value outside the four allowed tokens — aria-sort="asc" is invalid and ignored.
  • Forgetting that the header must be activatable by keyboard. aria-sort does not make the column header focusable; that’s on you.
  • Treating aria-sort as the source of truth instead of derived from your sort state. After a re-render that loses the attribute, the announcement disappears.

Example

<table>
  <thead>
    <tr>
      <th
        scope="col"
        aria-sort="ascending"
      >
        <button type="button">Last name</button>
      </th>
      <th scope="col" aria-sort="none">
        <button type="button">First name</button>
      </th>
      <th scope="col">Email</th>
    </tr>
  </thead>
  <tbody>
    <!-- … rows sorted by Last name ascending -->
  </tbody>
</table>