Skip to content

fix: correct pagination semantics on default render path#713

Open
ZQDesigned wants to merge 14 commits into
react-component:masterfrom
ZQDesigned:fix/a11y-aria-labels
Open

fix: correct pagination semantics on default render path#713
ZQDesigned wants to merge 14 commits into
react-component:masterfrom
ZQDesigned:fix/a11y-aria-labels

Conversation

@ZQDesigned

@ZQDesigned ZQDesigned commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Summary

This is a follow-up fix for the accessibility changes in #690.

The previous update improved labels, but antd integration still exposed a few a11y issues on the default render path:

  • invalid interactive semantics on ul > li
  • broken list semantics
  • nested interactive controls when consumers pass interactive prevIcon / nextIcon

This change keeps the useful a11y improvements from #690, while fixing the remaining semantic issues.

Changes

  • move default pagination interaction to the real inner controls
    • page items render inner native buttons
    • prev / next / jump-prev / jump-next render inner native buttons
    • wrapper li keeps list semantics only
  • move aria-label, aria-current, and title to the real interactive element
  • keep itemRender compatibility fallback for custom renderers
    • remove invalid wrapper role="button"
    • stop forcing child content to be aria-hidden
  • flatten interactive icon wrappers on the default path
    • if consumers pass a button or a as prevIcon / nextIcon / jump icons, only their content is reused
    • this avoids nested interactive controls in downstream integrations
  • update styles so button-based default items keep the same visual behavior

Tests

  • update pagination interaction tests for the default button-based path
  • keep coverage for custom itemRender fallback behavior
  • update snapshots for the semantic DOM changes

Verification

Verified in rc-pagination:

  • npx rc-test --no-watchman

Verified against antd integration with the packed local build:

  • components/pagination/__tests__/a11y.test.ts
  • components/list/__tests__/a11y.test.ts
  • components/table/__tests__/a11y.test.ts

Related

Summary by CodeRabbit

  • 新功能
    • 分页新增默认控制按钮渲染模式(prev/next/jump),在默认模式下图标包装为按钮时交互与键盘触发更一致。
    • Pager 支持 defaultItemRender 控制是否走默认渲染分支,并调整页码标签回退逻辑。
  • Bug 修复
    • 优化分页项在悬停/聚焦/禁用场景下的样式与可访问性标识(aria/title/aria-current 等)表现。
  • 测试
    • 将键盘交互从同步事件迁移为异步 user-event;收窄断言到按钮层级,并补充默认渲染与图标可交互场景用例。

@vercel

vercel Bot commented Jul 8, 2026

Copy link
Copy Markdown

@ZQDesigned is attempting to deploy a commit to the afc163's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cdab524c-502b-478b-81d1-be3b283e1003

📥 Commits

Reviewing files that changed from the base of the PR and between 3d45846 and 6aeae4c.

⛔ Files ignored due to path filters (1)
  • tests/__snapshots__/demo.test.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (3)
  • src/Pager.tsx
  • src/Pagination.tsx
  • tests/index.test.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/Pager.tsx
  • src/Pagination.tsx
  • tests/index.test.tsx

Walkthrough

本次改动为分页组件引入基于原生 button 的默认渲染路径,并同步调整 Pager/Pagination 的交互语义、样式选择器和测试。

Changes

默认按钮渲染重构

Layer / File(s) Summary
Pager 默认渲染分支与类型
src/Pager.tsx
PagerProps 新增 defaultItemRender?: boolean,Pager 按该标记切换默认 button 分页项与自定义 itemRender 路径,并调整 titlearia-labelaria-current 和 disabled 处理。
默认控制按钮渲染
src/Pagination.tsx
新增默认渲染判定与图标/按钮内容辅助函数,并通过 pagerProps 将默认渲染标记传入 Pager。
prev/next 控件渲染与可访问性
src/Pagination.tsx
prev/next 的渲染按默认与自定义分流,调整 li 的交互、禁用状态、titlearia-labeltabIndexrole 处理。
jump-prev/jump-next 控件重构
src/Pagination.tsx
jump-prev/jump-next 在默认渲染时改用默认按钮输出,自定义渲染时保留 itemRender 内容并调整交互与可访问性属性。
分页控件样式适配 button 元素
assets/index.less
样式选择器从仅覆盖 a 扩展为同时覆盖 abutton,包含基础布局、hover/focus/focus-within、伪元素符号和 disabled 状态。
测试更新以匹配 button 化交互
tests/index.test.tsx, tests/itemRender.test.tsx, tests/jumper.test.tsx
测试改为通过 button 触发点击与键盘交互,并新增默认渲染路径下图标包装扁平化的断言。

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Suggested reviewers: zombieJ

Poem

小兔跳进分页栏,
button 轻轻换新装;
焦点一落声清亮,
键盘一按路更长。
🐇 叶片翻动,测试也歌唱

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确概括了本次 PR 的核心改动:修复默认渲染路径下的分页语义问题。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request improves the accessibility and semantic structure of the Pagination component by introducing semantic elements for navigation items (prev, next, and jump controls) and supporting both Enter and Space keys for keyboard interaction. The feedback focuses on several key areas of improvement: preventing potential string coercion of undefined in pageLabel which would degrade screen reader experiences, cleaning up unused code (such as the type parameter in renderDefaultControlButton and the PaginationItemType definition), and consistently using undefined instead of null for React props to correctly omit attributes from the DOM.

[!IMPORTANT]
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/Pager.tsx Outdated
Comment thread src/Pagination.tsx Outdated
Comment thread src/Pagination.tsx
Comment thread src/Pagination.tsx
Comment thread src/Pagination.tsx
Comment thread src/Pagination.tsx
Comment thread src/Pagination.tsx Outdated
Comment thread src/Pagination.tsx Outdated
Comment thread src/Pagination.tsx Outdated
Comment thread src/Pagination.tsx Outdated
@ZQDesigned ZQDesigned marked this pull request as ready for review July 8, 2026 16:49
Copilot AI review requested due to automatic review settings July 8, 2026 16:49

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/Pager.tsx (1)

60-75: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

建议以显式布尔值判断 disabled,避免依赖类名字符串匹配。

disabled={cls.includes(${prefixCls}-disabled)} 依赖对完整类名字符串做子串匹配来推断禁用态。这一方式之所以“能工作”,是因为 noPager 场景通过 className 传入的 rc-pagination-item-disabled 恰好等于 ${prefixCls}-disabled;但仅用 !page 又会漏掉该场景。这种与类名字符串的隐式耦合较脆弱,后续若调整类名或新增包含该子串的类名可能引入难以察觉的回归。建议由父组件显式传入禁用标记并直接使用。

♻️ 可选实现思路(引入显式 disabled 语义)
 export interface PagerProps extends Pick<PaginationProps, 'itemRender'> {
   rootPrefixCls: string;
   page: number;
   pageLabel?: string;
   defaultItemRender?: boolean;
+  disabled?: boolean;
   active?: boolean;
-          disabled={cls.includes(`${prefixCls}-disabled`)}
+          disabled={!page || disabled}

调用处(Pagination.tsxnoPager 分支)以 disabled prop 取代 className={${prefixCls}-item-disabled} 传值。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Pager.tsx` around lines 60 - 75, `Pager` 里按钮的 `disabled` 现在通过
`cls.includes(...)` 依赖类名字符串推断,和样式命名耦合过紧。请在 `Pager.tsx` 的
`defaultItemRender`/按钮渲染逻辑中改为直接使用显式的禁用标记,并让 `Pagination.tsx` 的 `noPager`
分支把这个状态作为 prop 传给 `Pager`,不要再用 `className` 间接表达。这样 `disabled` 的判断只依赖业务状态而不是
`prefixCls` 生成的类名。
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/Pager.tsx`:
- Around line 60-75: `Pager` 里按钮的 `disabled` 现在通过 `cls.includes(...)`
依赖类名字符串推断,和样式命名耦合过紧。请在 `Pager.tsx` 的 `defaultItemRender`/按钮渲染逻辑中改为直接使用显式的禁用标记,并让
`Pagination.tsx` 的 `noPager` 分支把这个状态作为 prop 传给 `Pager`,不要再用 `className` 间接表达。这样
`disabled` 的判断只依赖业务状态而不是 `prefixCls` 生成的类名。

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6b08f5be-46ed-4571-b853-5ad498f1c856

📥 Commits

Reviewing files that changed from the base of the PR and between 61ee8c0 and beca892.

⛔ Files ignored due to path filters (2)
  • tests/__snapshots__/demo.test.tsx.snap is excluded by !**/*.snap
  • tests/__snapshots__/simple.test.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (6)
  • assets/index.less
  • src/Pager.tsx
  • src/Pagination.tsx
  • tests/index.test.tsx
  • tests/itemRender.test.tsx
  • tests/jumper.test.tsx

Copilot AI left a comment

Copy link
Copy Markdown

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 refines rc-pagination’s default DOM structure to use native <button> controls for pagination interactions (prev/next/jump/page), keeping <li> elements as list semantics only, and updates styling/tests/snapshots accordingly to address remaining accessibility issues after #690.

Changes:

  • Move default pagination interaction/ARIA attributes from wrapper <li> nodes to inner native <button> elements.
  • Flatten interactive icon wrappers on the default path to avoid nested interactive controls when consumers pass <button>/<a> icons.
  • Update Less styles plus unit tests and snapshots to match the new semantic DOM.

Reviewed changes

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

Show a summary per file
File Description
tests/jumper.test.tsx Adjust DOM queries to target the new inner <button> for next navigation.
tests/itemRender.test.tsx Add coverage for custom itemRender fallback wrapper interaction; update imports for new events.
tests/index.test.tsx Update assertions and keyboard interaction tests to use the new button-based DOM (including userEvent).
tests/snapshots/simple.test.tsx.snap Snapshot updates reflecting button-based semantics and moved ARIA attributes.
tests/snapshots/demo.test.tsx.snap Snapshot updates reflecting button-based semantics and moved ARIA attributes across demos.
src/Pagination.tsx Core logic to render native buttons on the default path; flatten icon wrappers; move ARIA/title to actual controls.
src/Pager.tsx Page items render as native buttons on the default path; non-default path keeps wrapper-driven interaction.
assets/index.less Style updates so <button>-based items match existing visuals, including focus/hover/disabled states.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Pagination.tsx
Comment thread src/Pager.tsx
Comment thread src/Pagination.tsx
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.

2 participants