Skip to content

Fix incorrect role and focus order in Pagination component #1009

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

joshfarrant
Copy link
Contributor

@joshfarrant joshfarrant commented May 14, 2025

Summary

Fixed two reported bugs in the Pagination component, as well as an additional bug uncovered during the course of this work.

List of notable changes:

This may look like more of a refactor than it is. Check individual commits for more info, but the key changes are:

  • Renamed the usePaginationPages hook to PaginationItem as it was behaving more like a component than a hook; it accepted a props object and returned JSX
  • Unified the attribute calculation and component rendering logic by removing buildComponentData from model.ts and instead put that logic inside the PaginationItem component.
  • Updated stories to allow controls to be used across all stories
    • While not necessary for this work, this change makes it easier for the component to be manually tested in Storybook.
  • Added a load of new tests to better assert the expected behaviour of the component.

The majority of the key logic hasn't changed, it's just been moved around and simplified slightly.

Bonus HTML!

I also grabbed the rendered HTML from the Pagination component before and after these changes and dropped them into a couple of quick diffs so you can more easily see the changes to the rendered markup

Note the following changes:

  • Previous & Next buttons both now have role="button"
  • tabindex="0" has been removed from all elements as it's not necessary since we're using the browser's default tab order. This also resolves https://github.com/github/primer/issues/3734 by removing tabindex from the ellipsis
  • as="span" has been removed from the ellipsis element. This was leaking through to the DOM due to as="span" not being a valid prop on our Link component. The previously described refactor and improved typing will prevent this category of issues from happening in the future.
  • When the Previous & Next buttons were disabled, their aria-label was removed. This PR also resolves that bug.

What should reviewers focus on?

  • Test the component and make sure it works as expected.
  • I've added tests to cover this, but check all of the expected attributes are still in the right place.

Steps to test:

I've added controls to all Pagination stories, so poke around in Storybook to check everything.

Supporting resources (related issues, external links, etc):

Contributor checklist:

  • All new and existing CI checks pass
  • Tests prove that the feature works and covers both happy and unhappy paths
  • Any drop in coverage, breaking changes or regressions have been documented above
  • UI Changes contain new visual snapshots (generated by adding update snapshots label to the PR)
  • All developer debugging and non-functional logging has been removed
  • Related issues have been referenced in the PR description

Reviewer checklist:

  • Check that pull request and proposed changes adhere to our contribution guidelines and code of conduct
  • Check that tests prove the feature works and covers both happy and unhappy paths
  • Check that there aren't other open Pull Requests for the same update/change

Copy link

changeset-bot bot commented May 14, 2025

🦋 Changeset detected

Latest commit: d2397f3

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 7 packages
Name Type
@primer/react-brand Patch
@primer/brand-docs Patch
@primer/brand-primitives Patch
@primer/brand-e2e Patch
@primer/brand-fonts Patch
@primer/brand-config Patch
@primer/brand-storybook Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link
Contributor

github-actions bot commented May 14, 2025

🟢 No design token changes found

case 'BREAK': {
key = `page-${page.num}-break`
content = '…'
Object.assign(props, {as: 'span', role: 'presentation'})
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the previous implementation, this as wasn't working as expected. The element was still rendered as an <a> despite the as prop here.

Note the rendered HTML:

image

This contributed (along with the tabIndex set here) to them still being focusable, and causing https://github.com/github/primer/issues/3734

Copy link
Contributor

github-actions bot commented May 14, 2025

🟢 No visual differences found

Our visual comparison tests did not find any differences in the UI.

@joshfarrant joshfarrant force-pushed the joshfarrant/pagination-a11y-fixes branch from 1dc82c9 to 78f8e2c Compare May 15, 2025 08:17
@joshfarrant joshfarrant changed the title Joshfarrant/pagination a11y fixes Fix incorrect role and focus order in Pagination component May 15, 2025
@joshfarrant joshfarrant force-pushed the joshfarrant/pagination-a11y-fixes branch from 78f8e2c to 8f9bf5f Compare May 15, 2025 11:13
@joshfarrant joshfarrant force-pushed the joshfarrant/pagination-a11y-fixes branch from 2cd62ed to c58a3d1 Compare May 15, 2025 11:45
@joshfarrant joshfarrant force-pushed the joshfarrant/pagination-a11y-fixes branch from c58a3d1 to dced700 Compare May 15, 2025 12:16
@joshfarrant joshfarrant force-pushed the joshfarrant/pagination-a11y-fixes branch from dced700 to 31fe3e8 Compare May 15, 2025 12:18
@joshfarrant joshfarrant marked this pull request as ready for review May 15, 2025 12:21
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR refactors the Pagination component to centralize page rendering logic into a new PaginationItem component, fixes accessibility bugs around roles and focus behavior, and updates tests and stories to the StoryObj format.

  • Renamed and relocated pagination item logic, removing buildComponentData in favor of an inline PaginationItem
  • Fixed role, tabindex, and aria-label issues on ellipsis and prev/next buttons
  • Updated tests (added new assertions) and migrated stories to StoryObj API

Reviewed Changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/react/src/Pagination/model.ts Updated PageType definition and buildPaginationModel
packages/react/src/Pagination/Pagination.tsx Introduced PaginationItem component and removed old hook
packages/react/src/Pagination/Pagination.test.tsx Added new tests and fixed existing test logic
packages/react/src/Pagination/Pagination.visual.spec.ts Removed outdated default visual test
packages/react/src/Pagination/Pagination.stories.tsx Migrated to StoryObj format
packages/react/src/Pagination/Pagination.features.stories.tsx Migrated to StoryObj and updated meta inheritance
.changeset/nine-cycles-pump.md Documented accessibility fixes


type PageType = {
type: string
export type PageType = {
Copy link
Preview

Copilot AI May 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PageType definition is missing the precedesBreak property, but buildPaginationModel includes precedesBreak on NUM pages. Add precedesBreak?: boolean to PageType.

Copilot uses AI. Check for mistakes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

precedesBreak?: boolean

Come on now :copilot:, keep up

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant