Start with the task, not the icon

A sortable table is useful when people need to compare the same records by more than one attribute. A delivery history might need newest first when a customer is looking for a recent parcel, but oldest first when they are reconciling a statement. A list of service appointments may need a date order but gain little from sorting by an internal reference. Watch a few realistic tasks and ask which order changes the next action. If one natural order answers nearly every task, a fixed order with a clear caption may be easier to understand and maintain than several controls that promise choice without value.

Separate the question of whether a column is sortable from whether the data can be sorted truthfully. A displayed price can mix sale prices, ranges, and unavailable items; a simple string comparison would put those rows in a misleading order. Dates may be shown in a localized format while the underlying values are timestamps. A business must define what missing values, ties, and mixed units mean before adding a heading control. A customer should not have to discover that “lowest price” means alphabetical order of formatted text or that blank prices were silently treated as zero.

Make the control and state clear

The W3C sortable-table example keeps ordinary HTML table structure and places a button inside each sortable column heading. This matters because the table remains a table while the heading becomes an actual control with built-in keyboard behavior. Give the table a caption that names its contents and, where useful, briefly explains that marked headings can change the order. Do not make a bare heading clickable through pointer events alone. If a column cannot produce a meaningful order, leave it as a heading rather than decorating it with a misleading arrow.

After a sort, the visible rows and the announced state must agree. The W3C example places aria-sort on the header of the currently sorted column, using ascending or descending as appropriate, and moves that attribute when another column becomes active. Treat the arrow as a visual cue, not the only explanation: direction needs an accessible state and a shape that survives colour changes. Decide what pressing the same header again does, then keep that rule consistent. A person should be able to tell both which field controls the present order and which way that field is running.

Specify the ordering rules

Build the comparison from raw, typed values, not from labels already formatted for display. A date key should represent a date or instant; a monetary key should represent an amount in the same currency and a known price basis. If a table shows HKD and another currency, either normalize with a disclosed basis or avoid a single price sort. For names, choose locale-aware comparison appropriate to the language shown, and do not assume English alphabetical order is a good order for Chinese names. These are product decisions because the resulting sequence changes what customers see first.

Write down a tie breaker so the order does not jump unpredictably when several records share the same value. For example, orders with the same displayed date can retain their previous order or use a stable order identifier; choose one rule and make it reproducible. Missing values need a deliberate position, often after known values in either direction, and a visible label such as “not available.” Avoid silently moving empty rows to the top when the user reverses a sort. If the page filters data, state whether sorting applies to all matching records or only the visible page; otherwise a result may appear sorted while relevant records remain hidden elsewhere.

Walk through a real comparison

Imagine a customer checking six recent service bookings. Two bookings share a day, one has an unconfirmed time, and the page initially shows the next appointment first. The customer selects the date heading to look from earliest to latest. The system sorts confirmed bookings by their actual scheduled time, places the unconfirmed entry according to a published rule, and keeps a stable order for equal times. The caption says these are upcoming bookings, the active date heading exposes ascending order, and the visible row sequence matches it. No result is lost from another page because the order is applied to the full filtered set before pagination.

Now try the same task on a narrow phone and with a keyboard. The heading button needs a usable target and a focus indicator; the changed order should remain understandable without relying only on coloured arrows. The customer should still be able to associate each booking with its row and column labels when the table scrolls horizontally. If the design instead turns every row into a card, check whether the sort choice and its state remain visible above the cards. The mobile presentation may change, but the promise made by the sort control and the underlying ordered set must stay the same.

Test the journey and decide when to simplify

Test more than whether rows visibly move. Start from the default order, activate each sortable heading by keyboard, reverse direction, then switch columns; inspect the DOM and use a screen reader to check that only the active heading carries the correct aria-sort value. Repeat after filtering, moving to another page, returning through browser navigation, and switching language if the site supports both. Test empty results, a single row, ties, missing values, and long names. W3C warns that its example is illustrative and that browser and assistive technology combinations, particularly touch setups, require real testing before production use.

If users mainly need one answer, a dedicated filter or search may solve the task more directly than sorting a dense table. A customer looking for one invoice number should search that number; a customer asking which deliveries remain outstanding may need a status filter. Sorting remains valuable when the person must compare multiple records in context. Review observed support questions and customer tasks after launch, but do not treat a high count of clicks on the arrows as proof that the order helped anyone. The decision is whether people can find and compare the intended records accurately, across devices and input methods.

If the table is server rendered, make the chosen sort key and direction part of a shareable page state when that helps people return to the same comparison. A URL parameter can do this, but it must be checked against an allowlist of supported keys and directions; it should not become an arbitrary database expression. If the table is entirely client side, preserve the selection when a user opens a detail and returns, where the task calls for it. In both approaches, the caption and active heading should reflect the reconstructed order after refresh. A control that forgets its state while still showing an old arrow is worse than a simple default order.

Sorting and filtering together deserve a separate rehearsal. Imagine a retailer has filtered a service list to open bookings, sorts by earliest date, then removes the filter. The application should define whether the date ordering remains active over the wider set and display that choice visibly. If a new record arrives while the customer compares rows, automatic resorting might make the row under their pointer move; a refresh notice or deliberate update can be safer. These details affect whether someone selects the intended record, especially when each row contains a consequential action such as rescheduling or cancelling. Test with realistic data changes, not only a frozen sample.

Give the implementation team a short acceptance note for each sortable column: what question it serves, what value is compared, where unknown values go, what the tie breaker is, and how state appears visually and to assistive technology. This makes review possible without reading the sorting code. It also exposes contradictions early, such as an “availability” order that mixes in-stock items, preorder items, and products with unknown stock. When the semantics are unclear, remove that sort choice until the business can define it. A smaller set of honest controls is more useful than a universal sort menu whose labels overpromise precision.

Before you proceed

  • Identify a customer task that changes when the row order changes.
  • Define typed values, ties, blanks, language and pagination before coding.
  • Test visual order, keyboard use and announced sort state together.

Sources & further reading