Accessible Pagination

This is an example of accessible pagination, designed for standard page-navigating content.

See Accessible Pagination for Single-Page Applications for a non-navigating adaptation.

In essence, pagination is just a bunch of links. But the structure, states, and even the appearance, require careful consideration to ensure that their meaning is perceivable and understandable by all users.

Pagination demo

Notes about this example

The semantic structure of this example is a <nav> element, with [aria-label="Pagination"] to disambiguate it from any any other navigation regions on the page. It contains two <ul> elements for the "First"/"Previous" and "Next"/"Last" links (unordered because the ordering within each pair is arbitrary), either side of an <ol> element for the individual page links (the order of which is a meaningful sequence). Whichever link corresponds with the current page uses [aria-current="page"] to convey this to assistive technologies, which will generally announce current page as part of the link description. These semantics ensure that the content conforms to 1.3.1 Info and Relationships and 4.1.2 Name, Role, Value, while the overall order of the links conforms to 2.4.3 Focus Order.

There are states in which particular links are unavailable. The "First" and "Previous" links are unavailable when viewing the first page (likewise the "Next" and "Last" links when viewing the last page), and whichever link corresponds with the current page should also, arguably, be unavailable as well, since it would link to the same page. One way in which pagination often addresses this, is by making those items plain text rather than links, or by removing them entirely in the case of Previous/Next links. But making those items plain text would mean they're not in the Tab order, creating an inconsistent pattern of keyboard interaction, while removing them entirely would create inconsistent output. Both of those scenarios might be confusing for assistive technology users, or for users with a cognitive disability.

What this example does instead is apply [aria-disabled="true"], which conveys to assistive technologies that those links are unavailable. This attribute is also used to vary their visual styling, and is used by JavaScript to suppress their native action, so that you can't follow the link. This approach is not entirely uncontroversial, because it means that those elements are focusable but have no action, which itself may be potentially confusing. It seems like there's no perfect approach either way, each has benefits and drawbacks, but this approach seemed better overall.

Updating the [aria-current], [aria-disabled], and [href] attributes is done with JavaScript, in this example, but much of that could be done with server-side scripting instead.

The "First", "Previous", "Next", and "Last" links use Unicode symbols for their content, they do not use typographical symbols such as > (greater-than) or » (right-angled quotation mark), because that would be semantically incorrect. But all of the links have [aria-label] attributes anyway, to describe them more coherently for assistive technologies, with values such as "Previous Page", or "Page 1". These expanded values ensure conformance with 2.4.4 Link Purpose (In Context) and 2.4.9 Link Purpose (Link Only).

The styling uses color codes for the states of different links, but does not rely on color, there are also additional style changes to indicate those states. The current page link uses bold, no-underlining, and a change of border style, while the dimmed Previous/Next links use opacity rather than color changes. So the states are still perceivable to Windows High Contrast users, and to other users who have limited or no color vision. All of this ensures conformance with 1.4.1 Use of Color, while the colors themselves conform to 1.4.3 Contrast (Minimum).

The layout is implemented using flex, and is allowed to wrap when required. This ensures that it doesn't overflow the viewport when viewed with large fonts, on small screens, or at high zoom levels, conforming to 1.4.4 Resize text and 1.4.10 Reflow.