payloadcms / payloadcms/payload

Admin pagination: previous/next arrow buttons have no accessible name

Open Beginner friendly
#17,377 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

area: ui
Dominant language
TypeScript
Stars
44.8k
Forks
4.2k
Avg merge
2d 21h
Merged PRs (30d)
53

Description

Describe the Bug

The previous/next pagination arrows in the admin list view are icon-only buttons with no accessible name. Screen-reader users hear "button" with no indication of direction or purpose. axe-core reports this as a critical button-name violation.

Rendered markup, stock admin list view:

<button class="clickable-arrow clickable-arrow--is-disabled clickable-arrow--left" disabled type="button"></button>
<button class="clickable-arrow clickable-arrow--right" type="button"><svg class="icon icon--chevron" …></svg></button>
Root cause (verified on main)

ClickableArrow's only child is <ChevronIcon />, with no aria-label and no visually-hidden text:

https://github.com/payloadcms/payload/blob/6981acab5a8e15ae9d62da10672548b1616e0238/packages/ui/src/elements/Pagination/ClickableArrow/index.tsx#L26-L36

return (
  <button
    className={classes}
    disabled={isDisabled}
    onClick={!isDisabled ? updatePage : undefined}
    type="button"
  >
    <ChevronIcon />
  </button>
)

An icon-only button with no text content and no ARIA label has no accessible name.

Link to the code that reproduces this issue

The permalink above — this is stock admin markup, not configuration-dependent, so a scaffolded repo would only re-render Payload's own ClickableArrow. The file is unchanged on main at 6981acab5a8e15ae9d62da10672548b1616e0238. Happy to push a create-payload-app -t blank repo if you'd still like one; it would be the default template with no changes.

Reproduction Steps
  1. pnpx create-payload-app@latest -t blank
  2. Seed a collection with more than one page of documents.
  3. Open its list view and inspect the pagination arrows — or run axe-core.
  4. Observe neither button has an accessible name.
Which area(s) are affected?

area: ui

Environment Info
payload:         3.84.1
@payloadcms/ui:  3.84.1
Next.js:         16.2.6
Node:            25
Browser:         Chrome 141 (headless)
axe-core:        4.12.1

Root cause verified present in main at 6981acab5a8e15ae9d62da10672548b1616e0238.

Possible fix

An aria-label derived from direction ("Previous page" / "Next page") would resolve it. ChevronIcon could take aria-hidden at the same time, since the label would then carry the meaning.

Happy to open a PR if the direction is welcome.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with packages/ui/src/elements/Pagination/ClickableArrow/index.tsx and inspect how the direction reaches the button. Reproduce the admin list pagination case or run axe-core, then verify that both arrow buttons expose their direction and that the button-name violation is gone.

Written by the indexing model from the issue text.

Assessment

Tech stack
react, typescript
Domain
accessibility, frontend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.