Pagination is one of those components that are ubiquitous across the web. As designers and developers, we don’t always stop to think about how we can take such a common thing and improve upon it accessibility-wise.
Accessible pagination markup
While looking into pagination and accessibility, I came across this excellent article explaining how to improve pagination accessibility at Accessibility Matters by Ahmad Shadeed. After a thorough exploration of the possibilities, including some helpful recordings of how the different approaches sound to screen readers, this is the final recommended markup:
The important parts are:
- Place the pagination inside a
<nav>
element. Note that addingrole="navigation"
is redundant as the navigation role is implied by use of the<nav>
element - Include an
aria-label="pagination"
attribute on the<nav>
element to help describe the type of navigation contained within - Properly mark up the navigation as an unordered list
- Use the
aria-current="page"
attribute on the current page to help inform screen readers about the current page - Add an
aria-label
attribute to each link to help provide better information for screen readers
Creating accessible pagination in WordPress
After digging in, I couldn’t find a way to replicate that markup exactly in WordPress, but I was able to get really close, and to find another way to get similar results for screen reader users.
My solution makes use of WordPress’s paginate_links
function, which gives lots of options, allowing us to customize the output:
Let’s review how we’re addressing the important points:
- We’ve wrapped the entire pagination in a
<nav>
element - We added a (translatable)
aria-label
attribute to the<nav>
element to mark this as pagination - By specifying the
type
aslist
, WordPress outputs the links as an unordered list - WordPress automatically adds the
aria-current="page"
attribute to the current page for us - We’ve included helpful context for the individual page links by adding some extra hints for screen readers
I couldn’t find a simple or straightforward way to automatically add the aria-label
attribute to each link as recommended in Shadeed’s article. In his final code recommendation, he’s actually looping through those links with JavaScript to add that attribute. That gets a little tricky with WordPress as we might have dozens or hundreds of pages in our pagination, and WordPress has lots of nifty ways of altering the display so those remain usable without having to display all the page links.
What I landed on instead was adding that extra text in front of the link text and using the screen-reader-text
CSS class to hide that from sight while allowing screen readers to access that content. In the end, the result is the same for screen reader users, so I call that a success. Many, if not most, WordPress themes include a screen-reader-text
CSS class, but here is the one from _s (Underscores) just in case you need to add it to your child theme:
Adding next and previous buttons
In the WordPress code above, I’m intentionally preventing next and previous buttons from displaying before and after my pagination numbers. If you prefer to include those, you can pass a few extra parameters to the paginate_links
function to customize the content for those as well to make them as friendly to screen readers as possible. For example, if you wanted to use Font Awesome icons for the next and previous buttons, but still have helpful text for screen readers:
Inclusively-designed pagination
In addition to making the markup itself as friendly as possible to assistive technologies, you’ll also want to carefully consider the design of the pagination. Just a few quick tips on pagination design:
- Style all the states: You have the regular page links which will have a link style as well as a hover/focus style. But you also have the current page and the next/previous buttons to style as well.
- Color contrast: Make sure to test the color contrast of any background/foreground color combinations, including the current page and hover states.
- Add lots of padding around the links: a single character makes for a small target to try to hit with a mouse or a finger. Make pagination links easier to hit by adding at least 1em of padding on the left and right, and at least 0.5em of padding on the top and bottom.
- Font size: Make sure the font size for the pagination is at least 16 pixels. 20 or 24 is even better.
- Remember to add a focus style: Keyboard users will need to be able to visually see which link has focus, so be sure to add a style for the
:focus
state to the page links and the next/previous links.
Sometimes it just takes a couple extra minutes of thoughtfulness to take a just-okay page component and turn it into something that is accessible and usable for as many people as possible.
Hi Natalie, Thank you for this article. It was easy to follow your instructions and to implement. I also appreciate the review points and additional tips.
My hope now is to take this a step further, once I get up-to-speed with WordPress’s paginate_links function, to customize the output. The project I’m working on now requires that the … dots argument be removed, but I haven’t quite figured out how to augment your code to make this happen. Wish me luck and appreciate any additional pointers on this.
Hi Kathy! Glad this was helpful for you. If you want to remove the ellipsis and instead show all the pagination numbers, I believe you need to set the ‘show_all’ argument to true as shown in the documentation: https://developer.wordpress.org/reference/functions/paginate_links/
Hey thanks for posting these examples. However, I’m not having any luck with your code example. The ‘before_page_number’ parameter breaks my pagination. I copied and pasted from your example, only updating the text domain. It closes the anchor tag prematurely. It puts the closing after the screen reader span but before the number. So it goes:
<a href="[url]" rel="nofollow ugc">screenreader text</a> [number].
So the links no longer work on the actual number itself.
Hi Ryan! Sorry that it’s giving you trouble. I’ve copied and pasted this code and used it on many sites with no issues, so I’m not sure why it’s not working for you. I double-checked all the code snippets here and don’t see any typos or errors. Are you using the example with next/prev buttons or without?