Skip to content

feat: 添加组件无障碍功能支持 - #3383

Draft
yangyanAurora wants to merge 57 commits into
jdf2e:feat_v3.xfrom
yangyanAurora:feat_v3.x
Draft

yangyanAurora wants to merge 57 commits into
jdf2e:feat_v3.xfrom
yangyanAurora:feat_v3.x

Conversation

@yangyanAurora

@yangyanAurora yangyanAurora commented Nov 10, 2025 •

Copy link
Copy Markdown
  • button
  • Checkbox
  • Countdown
  • Empty
  • Image
  • InputNumber
  • Price
  • Progress
  • NavBar
  • NoticeBar
  • Radio
  • Switch
  • Tabbar
  • Tabs
  • Toast

🤔 这个变动的性质是?

  • [ ☑️ ] 新特性提交
  • 日常 bug 修复
  • 站点、文档改进
  • 演示代码改进
  • 组件样式/交互改进
  • TypeScript 定义更新
  • 包体积优化
  • 性能优化
  • 功能增强
  • 国际化改进
  • 重构
  • 代码风格优化
  • 测试用例
  • 分支合并
  • 其他改动(是关于什么的改动?)

🔗 相关 Issue

💡 需求背景和解决方案

为让更多人(包括残障人士)能够平等、便捷地使用和访问应用,对组件提升对无障碍的支持。

☑️ 请求合并前的自查清单

⚠️ 请自检并全部勾选全部选项。⚠️

  • [ ☑️ ] 文档已补充或无须补充
  • [ ☑️ ] 代码演示已提供或无须提供
  • [ ☑️ ] TypeScript 定义已补充或无须补充
  • [ ☑️ ] fork仓库代码是否为最新避免文件冲突
  • [ ☑️ ] Files changed 没有 package.json lock 等无关文件

Summary by CodeRabbit

新功能

  • 多个组件新增无障碍支持:添加ARIA标签、角色和属性,增强屏幕阅读器兼容性
  • 倒计时组件:新增结束时的通知提醒功能
  • 交互组件改进:为按钮、复选框、单选、开关、标签栏等添加ARIA角色和状态属性
  • 图片、导航栏、价格等组件:添加文字标签用于屏幕阅读

xiaoyatong and others added 30 commits August 7, 2025 11:07
* fix: 暂时屏蔽掉css transition

* fix: cpp 下class类问题
* chore(release): v3.0.18

* fix(swiper): duration属性透传 (jdf2e#3337)

* feat: 修复属性透传

* feat: 直接删除duration

* fix(range): taro环境异步渲染useReady不会触发 (jdf2e#3297)

* fix(range): taro环境异步渲染useReady不会触发

* refactor: 将组件中使用的useReady替换为useLayoutEffect

* chore: 升级版本号

* feat(popup): 增加上下滑动修改高度

* fix(input): 兼容h5和小程序获取原生input标签 (jdf2e#3341)

* feat: inputRef获取真实input-dom

* feat: 兼容小程序和h5获取input标签

* feat: 取消?问好,出错直接抛出

* feat(Popup): 新增弹层可上下滑动 (jdf2e#3340)

* feat: 支持popup 高度可以伸缩

* feat: 适配小程序

* feat: 修改文档

* fix: 默认值不需要,走样式

* feat: 增加使用的限制条件

* docs: 增加文档

* fix: 适配鸿蒙,初始值重置修改

* test: 添加单测

* fix: 增加h5 的初始值

* fix: 增加高度下限约束

* test: fix 单测

* feat(popup): 添加自定义顶部

* fix(input): taro 下只读可以点击

---------

Co-authored-by: Alex.hxy <1872591453@qq.com>
Co-authored-by: YONGQI <holyfata@qq.com>
Co-authored-by: RyanCW <75795462+Ryan-CW-Code@users.noreply.github.com>
* feat: 鸿蒙适配td

* chore: 强制指向某些版本

* fix: swipe 在鸿蒙下不好使的问题

* fix(toast): 无法在鸿蒙下换行的问题

* fix: 调整滑动时动效时间

* fix: 去掉注释

* chore: 升级nutui版本

* chore: 升级版本号

* fix: lint
@github-actions github-actions Bot added action:review This PR needs more reviews (less than 2 approvals) 3.x Target branch 3.x labels Nov 10, 2025
@coderabbitai

coderabbitai Bot commented Nov 10, 2025 •

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

此PR为NutUI React组件库的多个组件系统添加ARIA可访问性属性支持,包括角色、标签、选中状态等属性,同时新增相关演示和类型定义,以改进屏幕阅读器兼容性。

Changes

Cohort / File(s) 变更摘要
按钮组件可访问性
src/packages/button/button.taro.tsx
添加 ariaLabel="button" 属性到TaroButton元素以增强可访问性。
复选框组件可访问性
src/packages/checkbox/checkbox.taro.tsx, src/packages/checkbox/checkbox.tsx
添加 ariaRole="checkbox" 和 ariaChecked 属性,反映复选框的选中和非不定状态。
倒计时组件ARIA增强
src/packages/countdown/countdown.taro.tsx, src/packages/countdown/countdown.tsx
添加 ariaRoledescription 属性,实现倒计时结束时的ARIA alert提示("时间到")。
倒计时演示和翻译
src/packages/countdown/demo.taro.tsx, src/packages/countdown/demo.tsx, src/packages/countdown/demos/h5/demo10.tsx, src/packages/countdown/demos/taro/demo10.tsx
添加新演示组件Demo10和国际化翻译支持。
对话框ARIA支持
src/packages/dialog/content.taro.tsx, src/packages/dialog/content.tsx, src/packages/dialog/dialog.taro.tsx, src/packages/dialog/dialog.tsx
添加 role="dialog"、aria-modal 和内容特定的ARIA属性。
图片组件可访问性
src/packages/image/image.taro.tsx, src/packages/image/image.tsx, src/packages/image/demo.taro.tsx, src/packages/image/demo.tsx, src/packages/image/demos/h5/demo9.tsx, src/packages/image/demos/taro/demo9.tsx
添加 ariaLabel 属性及演示。
数字输入组件按钮角色
src/packages/inputnumber/inputnumber.taro.tsx, src/packages/inputnumber/inputnumber.tsx
为加减按钮添加 role="button" 和 tabIndex 属性。
导航栏ARIA增强
src/packages/navbar/navbar.taro.tsx, src/packages/navbar/navbar.tsx, src/packages/navbar/demo.taro.tsx, src/packages/navbar/demo.tsx, src/packages/navbar/demos/h5/demo4.tsx, src/packages/navbar/demos/taro/demo4.tsx
添加 role="navigation"、返回按钮和标题的ARIA标签。
通知条ARIA增强
src/packages/noticebar/noticebar.taro.tsx, src/packages/noticebar/noticebar.tsx, src/packages/noticebar/demo.taro.tsx, src/packages/noticebar/demo.tsx, src/packages/noticebar/demos/h5/demo12.tsx, src/packages/noticebar/demos/taro/demo12.tsx
添加 rightIconAriaLabel 属性和隐藏图标的ARIA支持。
弹窗ARIA角色
src/packages/popup/popup.taro.tsx, src/packages/popup/popup.tsx
添加 role="dialog" 属性到弹窗容器。
价格组件ARIA标签
src/packages/price/price.taro.tsx, src/packages/price/price.tsx
添加基于符号和格式的动态 ariaLabel。
进度条ARIA支持
src/packages/progress/progress.taro.tsx, src/packages/progress/progress.tsx
添加 role="progressbar" 和 ariaLabel 属性。
单选框ARIA属性
src/packages/radio/radio.taro.tsx, src/packages/radio/radio.tsx
添加 role="radio"、tabIndex 和 aria-checked 属性。
开关组件ARIA增强
src/packages/switch/switch.taro.tsx, src/packages/switch/switch.tsx
添加 role="switch"、tabIndex 和 aria-checked 属性。
轮播图ARIA支持
src/packages/swiper/swiper.taro.tsx, src/packages/swiper/swiper.tsx, src/packages/swiper/effects/default.tsx, src/packages/swiper/effects/focus.tsx, src/packages/swiper/demo.taro.tsx, src/packages/swiper/demos/taro/demo10.tsx
添加 ariaLabel、aria-hidden 和 tabIndex 属性及演示组件。
标签栏ARIA增强
src/packages/tabbar/tabbar.taro.tsx, src/packages/tabbar/tabbaritem/tabbaritem.taro.tsx, src/packages/tabbar/tabbaritem/tabbaritem.tsx, src/packages/tabbar/demo.taro.tsx, src/packages/tabbar/demo.tsx, src/packages/tabbar/demos/h5/demo10.tsx, src/packages/tabbar/demos/taro/demo10.tsx
添加 role="tab"、aria-selected、ariaLabel 和 ariaRoledescription 属性。
标签页ARIA支持
src/packages/tabs/tabs.taro.tsx, src/packages/tabs/tabs.tsx
添加 role="tablist"、role="tab" 和 aria-selected 属性。
提示框ARIA角色
src/packages/toast/Notification.tsx, src/packages/toast/toast.taro.tsx
添加 role="alert" 属性。
头部按钮ARIA
src/sites/components/header.tsx
添加返回按钮的 role="button" 和 aria-label 属性。
类型定义ARIA扩展
src/types/spec/countdown/base.ts, src/types/spec/dialog/base.ts, src/types/spec/dialog/taro.ts, src/types/spec/image/base.ts, src/types/spec/noticebar/base.ts, src/types/spec/popup/base.ts, src/types/spec/progress/base.ts, src/types/spec/radio/base.ts, src/types/spec/swiper/taro.ts, src/types/spec/tabbar/base.ts
添加ARIA相关属性类型定义到各组件的基础接口。

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

需要特别关注的区域:

  • 倒计时alert实现 — 验证"时间到"alert的3秒定时清除机制是否正确工作
  • 对话框role和aria-modal配置 — 确保role="dialog"与aria-modal的可视性绑定逻辑一致
  • 轮播图tab导航 — 检查tabIndex、aria-hidden和aria-label在多张幻灯片间的正确传播
  • 类型定义一致性 — 验证所有新增的ARIA属性类型定义与组件实现保持同步
  • 跨平台差异 — 确保Taro和Web版本的ARIA属性保持语义一致性

Possibly related PRs

Suggested reviewers

  • irisSong
  • oasis-cloud
  • Alex-huxiyang

Poem

🐰 兔子漫步在代码小径,
添加标签让视障者欢喜,
对话、标签、图片与开关,
无障碍之光闪闪发亮,
ARIA魔法让交互更有意义~✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed PR描述包含了必需的自查清单,标记了变动性质为新特性,说明了背景和解决方案,但缺少具体的相关Issue链接。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed PR标题清晰准确地反映了主要变更:为多个组件添加无障碍功能支持,这是一个新功能特性。

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


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 and usage tips.

@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.

Actionable comments posted: 32

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
src/packages/tabs/tabs.tsx (1)

161-213: 建议完善 ARIA Tabs 模式的实现

当前实现添加了基本的 ARIA 属性(role="tablist"、role="tab"、aria-selected),这是一个良好的开端。但完整的 ARIA Tabs 模式还需要以下增强:

  1. 键盘导航支持:应实现方向键(左/右或上/下)、Home、End 键的导航
  2. tabIndex 管理:活动标签应设置 tabIndex={0},非活动标签设置 tabIndex={-1}
  3. aria-controls:每个标签应通过 aria-controls 属性关联到对应的面板 ID

这些是 ARIA 规范中 Tabs 模式的必需特性,能显著提升键盘用户和屏幕阅读器用户的体验。

参考 ARIA Tabs 模式获取完整实现指南。

src/packages/inputnumber/inputnumber.tsx (2)

183-198: 建议完善按钮的无障碍实现

当前添加了 role="button" 和 tabIndex={0},使元素可聚焦,但还需要以下改进才能成为完整的可访问按钮:

  1. aria-label:添加描述性标签(如 aria-label="减少数值")
  2. aria-disabled:反映禁用状态 aria-disabled={Number(shadowValue) <= Number(min) || disabled}
  3. 键盘激活:添加 onKeyDown 处理程序以支持 Enter 和 Space 键激活

建议修改:

       <div
         className={`${classPrefix}-minus`}
         onClick={handleReduce}
         role="button"
         tabIndex={0}
+        aria-label="减少数值"
+        aria-disabled={Number(shadowValue) <= Number(min) || disabled}
+        onKeyDown={(e) => {
+          if (e.key === 'Enter' || e.key === ' ') {
+            e.preventDefault()
+            handleReduce(e as any)
+          }
+        }}
       >

212-227: 增加按钮也需要完善的无障碍实现

与减少按钮类似,增加按钮也需要添加 aria-label、aria-disabled 和键盘激活支持。

建议修改:

       <div
         className={`${classPrefix}-add`}
         role="button"
         tabIndex={0}
         onClick={handlePlus}
+        aria-label="增加数值"
+        aria-disabled={Number(shadowValue) >= Number(max) || disabled}
+        onKeyDown={(e) => {
+          if (e.key === 'Enter' || e.key === ' ') {
+            e.preventDefault()
+            handlePlus(e as any)
+          }
+        }}
       >
src/packages/image/demo.tsx (1)

25-36: 修正拼写错误

翻译键名称中存在拼写错误。应该是 "ARIA"(Accessible Rich Internet Applications),而不是 "ATRIA"。

应用此修复:

-      ATRIAUsage: 'ATRIA用法',
+      ARIAUsage: 'ARIA用法',
     },
     'en-US': {
       basic: 'Basic Usage',
@@ -32,7 +32,7 @@
       error: 'Error',
       lazyload: 'Lazyload',
       imageText: 'image + text ',
-      ATRIAUsage: 'ATRIA Usage',
+      ARIAUsage: 'ARIA Usage',
     },
🧹 Nitpick comments (18)
src/packages/toast/Notification.tsx (1)

137-137: 考虑为不同类型的 Toast 使用不同的 ARIA 角色

当前为所有 Toast 类型统一使用 role="alert"。虽然这对于 success、fail、warn 等提示类消息是合适的,但对于 loading 类型的 Toast,role="status" 可能更为恰当,因为:

  • role="alert" 隐式设置了 aria-live="assertive",会立即打断屏幕阅读器
  • loading 状态更适合使用 role="status"(隐式 aria-live="polite"),以非打断方式通知用户

建议根据 Toast 类型动态设置 role:

          <div
            className={classNames(
              `${classPrefix}-inner`,
              `${classPrefix}-${position}`,
              contentClassName,
              `${classPrefix}-inner-${size}`,
              `${classPrefix}-inner-${wordBreak}`,
              {
                [`${classPrefix}-inner-descrption`]: content,
              }
            )}
            style={{
              ...contentStyle,
            }}
-           role="alert"
+           role={icon === 'loading' ? 'status' : 'alert'}
          >
src/packages/toast/toast.taro.tsx (1)

181-181: 建议为不同类型的 Toast 使用不同的 ARIA 角色

与 Notification.tsx 中的建议一致,Taro 版本也应该根据 Toast 类型动态设置 ariaRole:

  • 对于 loading 类型,使用 ariaRole="status" 更为合适(非打断式通知)
  • 对于 success、fail、warn 等类型,使用 ariaRole="alert" 是恰当的(立即通知)

建议应用以下修改:

            <View
              className={classNames(
                `${classPrefix}-inner`,
                `${classPrefix}-${position}`,
                contentClassName,
                `${classPrefix}-inner-${size}`,
                `${classPrefix}-inner-${wordBreak}`,
                {
                  [`${classPrefix}-inner-descrption`]: content,
                }
              )}
              style={{ ...styles, ...contentStyle }}
-             ariaRole="alert"
+             ariaRole={icon === 'loading' ? 'status' : 'alert'}
            >
src/packages/switch/switch.tsx (1)

85-93: 应根据禁用状态条件性地设置 tabIndex。

无障碍属性的添加总体良好,但 tabIndex={0} 应仅在组件未禁用时应用。当前实现即使在禁用状态下也会使元素可聚焦,这不符合无障碍最佳实践。

应用以下修改:

 <div
   className={classes()}
   onClick={onClick}
   style={style}
   {...rest}
   role="switch"
-  tabIndex={0}
+  tabIndex={disabled ? -1 : 0}
   aria-checked={value}
 >

另外,建议添加键盘事件处理器以支持空格键和回车键切换开关状态:

+const handleKeyDown = (e: React.KeyboardEvent) => {
+  if (e.key === ' ' || e.key === 'Enter') {
+    e.preventDefault()
+    onClick()
+  }
+}
+
 <div
   className={classes()}
   onClick={onClick}
+  onKeyDown={handleKeyDown}
   style={style}
   {...rest}
   role="switch"
   tabIndex={disabled ? -1 : 0}
   aria-checked={value}
 >
src/packages/checkbox/checkbox.taro.tsx (1)

206-207: 考虑为不确定状态添加 aria-checked="mixed" 支持

当前实现中,ariaChecked 在不确定状态(indeterminate)时值为 false,但根据 ARIA 规范,复选框的不确定状态应该使用 aria-checked="mixed" 来正确传达给辅助技术。

建议修改为:

       ariaRole="checkbox"
-      ariaChecked={innerChecked && !innerIndeterminate}
+      ariaChecked={
+        innerIndeterminate ? 'mixed' : innerChecked
+      }
src/packages/navbar/navbar.taro.tsx (2)

70-70: 建议支持 ARIA 标签的国际化

ariaLabel="back" 使用了硬编码的英文文本,这会影响非英语用户的无障碍体验。建议通过组件 props 或国际化系统来支持多语言的 ARIA 标签。


87-87: 标题的 ARIA 标签也需要国际化支持

与返回按钮类似,ariaLabel="nav title" 的硬编码英文文本应该支持国际化,以便为不同语言的用户提供适当的无障碍标签。

src/packages/inputnumber/inputnumber.taro.tsx (2)

185-200: 建议为按钮添加更完善的无障碍属性

当前只添加了 ariaRole="button",但缺少其他重要的无障碍属性:

  1. ariaLabel: 应该添加描述性标签(如 "减少数值"),让屏幕阅读器用户了解按钮用途
  2. ariaDisabled: 当按钮禁用时(值达到最小值或 disabled 为 true),应该设置 ariaDisabled={true} 来明确传达状态

建议修改:

       <View
         className={`${classPrefix}-minus`}
         onClick={handleReduce}
         ariaRole="button"
+        ariaLabel="减少数值"
+        ariaDisabled={Number(shadowValue) <= Number(min) || disabled}
       >

216-231: 增加按钮也需要完善的无障碍属性

与减少按钮类似,增加按钮也应该添加 ariaLabel 和 ariaDisabled 属性以提供完整的无障碍支持。

建议修改:

       <View
         className={`${classPrefix}-add`}
         onClick={handlePlus}
         ariaRole="button"
+        ariaLabel="增加数值"
+        ariaDisabled={Number(shadowValue) >= Number(max) || disabled}
       >
src/types/spec/countdown/base.ts (1)

30-30: 建议将 ariaRoledescription 设为可选属性

ariaRoledescription 通常不是所有倒计时场景都需要的属性。建议在类型定义中将其标记为可选:

-  ariaRoledescription: string
+  ariaRoledescription?: string

或者确保在组件的 defaultProps 中提供合理的默认值(如空字符串)。

src/packages/navbar/navbar.tsx (1)

69-69: 建议支持 ARIA 标签的国际化

与 Taro 版本类似,这里的 aria-label="back" 和 aria-label="nav title" 使用了硬编码的英文文本。建议通过组件 props 或国际化系统来支持多语言的无障碍标签,以便为全球用户提供适当的无障碍体验。

Also applies to: 86-86

src/packages/tabs/tabs.taro.tsx (2)

236-236: 检查冗余的角色属性

在同一个元素上同时使用了 role="tablist" 和 ariaRole="tablist"。在 Taro 中,通常只需要使用 ariaRole 属性,role 属性可能是冗余的。

建议验证 Taro 文档以确认正确的用法。如果只需要 ariaRole,可以移除 role 属性:

-        <View className="nut-tabs-list" role="tablist" ariaRole="tablist">
+        <View className="nut-tabs-list" ariaRole="tablist">

262-263: 验证 ariaHidden 属性语法

ariaHidden 属性没有显式设置值。在 Taro 中,建议明确设置布尔值。

建议明确设置为 true:

-                        ariaHidden
+                        ariaHidden={true}
src/packages/navbar/demos/taro/demo4.tsx (1)

1-113: ARIA 演示实现良好

此演示文件很好地展示了如何在 NavBar 组件中使用 ARIA 属性。各个交互元素都添加了适当的 ariaLabel,有助于屏幕阅读器用户理解界面。

可选建议:第 59 和 63 行的 ariaLabel 是添加在文本容器上的,这些元素不是交互元素,可以考虑是否需要这些标签。通常 aria-label 用于交互元素或需要替代文本的元素。

src/packages/countdown/countdown.tsx (1)

296-300: 避免在 dangerouslySetInnerHTML 中使用字符串插值

虽然当前代码中 role 和 alertContent 是组件内部控制的,没有直接的 XSS 风险,但使用 dangerouslySetInnerHTML 配合字符串插值不是最佳实践。建议使用 React 的 ARIA live region 方法来实现提醒功能。

建议重构为使用单独的元素和 React 状态:

-          aria-label="倒计时"
-          aria-roledescription={ariaRoledescription}
-          {...rest}
-          dangerouslySetInnerHTML={{
-            __html: `${renderTime}<span style="display:none" role=${role}>${alertContent}</span>`,
-          }}
+          aria-label="倒计时"
+          aria-roledescription={ariaRoledescription}
+          {...rest}
+        >
+          <div dangerouslySetInnerHTML={{ __html: renderTime }} />
+          {role && (
+            <span style={{ display: 'none' }} role={role}>
+              {alertContent}
+            </span>
+          )}
+        </div>
-        />

这样可以避免在 HTML 字符串中插值,更安全且更符合 React 最佳实践。

src/sites/components/header.tsx (1)

32-32: 返回按钮无障碍属性正确

为返回按钮添加 role='button' 和 aria-label='back' 提高了可访问性,有助于屏幕阅读器用户理解此元素的功能。

可选建议:为保持代码风格一致性,可以考虑使用双引号:

-          <div className="back" onClick={navigateTo} role='button' aria-label='back'>
+          <div className="back" onClick={navigateTo} role="button" aria-label="back">
src/packages/popup/popup.taro.tsx (1)

316-316: 建议添加 aria-modal 属性

当 Popup 作为对话框(dialog)呈现并且具有遮罩层时,应该添加 ariaModal 属性以向辅助技术指示这是一个模态对话框。这是 ARIA 对话框模式的最佳实践。

应用以下修改:

         onTouchEnd={handleTouchEnd}
         ariaRole="dialog"
+        ariaModal={overlay && innerVisible}
       >
src/packages/image/demos/taro/demo9.tsx (1)

9-9: 建议澄清 alt 和 ariaLabel 的使用场景

Image 组件同时使用了 alt="图片内容" 和 ariaLabel="图片"。对于图片元素,aria-label 会覆盖 alt 文本。通常情况下:

  • 仅使用 alt 即可满足大多数无障碍需求
  • aria-label 适用于需要为屏幕阅读器提供与 alt 不同的额外上下文时

建议在演示中明确两者的使用场景,或根据实际需求选择其一,避免混淆。

src/packages/noticebar/noticebar.tsx (1)

460-462: 建议显式设置 aria-hidden 值

虽然在 HTML/React 中,aria-hidden 不带值会被浏览器解析为字符串 "true",但显式设置布尔值 aria-hidden={true} 会更清晰且与 TypeScript 的类型检查更一致。

可选改进:

           {leftIcon ? (
-            <div className="nut-noticebar-box-left-icon" aria-hidden>
+            <div className="nut-noticebar-box-left-icon" aria-hidden="true">
               {leftIcon}
             </div>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e9a80b8 and 2e7cbd2.

📒 Files selected for processing (70)
  • src/packages/button/button.taro.tsx (1 hunks)
  • src/packages/checkbox/checkbox.taro.tsx (1 hunks)
  • src/packages/checkbox/checkbox.tsx (1 hunks)
  • src/packages/countdown/countdown.taro.tsx (4 hunks)
  • src/packages/countdown/countdown.tsx (4 hunks)
  • src/packages/countdown/demo.taro.tsx (5 hunks)
  • src/packages/countdown/demo.tsx (5 hunks)
  • src/packages/countdown/demos/h5/demo10.tsx (1 hunks)
  • src/packages/countdown/demos/taro/demo10.tsx (1 hunks)
  • src/packages/dialog/content.taro.tsx (2 hunks)
  • src/packages/dialog/content.tsx (2 hunks)
  • src/packages/dialog/dialog.taro.tsx (5 hunks)
  • src/packages/dialog/dialog.tsx (2 hunks)
  • src/packages/image/demo.taro.tsx (4 hunks)
  • src/packages/image/demo.tsx (4 hunks)
  • src/packages/image/demos/h5/demo9.tsx (1 hunks)
  • src/packages/image/demos/taro/demo9.tsx (1 hunks)
  • src/packages/image/image.taro.tsx (2 hunks)
  • src/packages/image/image.tsx (2 hunks)
  • src/packages/inputnumber/inputnumber.taro.tsx (2 hunks)
  • src/packages/inputnumber/inputnumber.tsx (2 hunks)
  • src/packages/navbar/demo.taro.tsx (2 hunks)
  • src/packages/navbar/demo.tsx (2 hunks)
  • src/packages/navbar/demos/h5/demo4.tsx (1 hunks)
  • src/packages/navbar/demos/taro/demo4.tsx (1 hunks)
  • src/packages/navbar/navbar.taro.tsx (3 hunks)
  • src/packages/navbar/navbar.tsx (3 hunks)
  • src/packages/noticebar/demo.taro.tsx (4 hunks)
  • src/packages/noticebar/demo.tsx (4 hunks)
  • src/packages/noticebar/demos/h5/demo12.tsx (1 hunks)
  • src/packages/noticebar/demos/taro/demo12.tsx (1 hunks)
  • src/packages/noticebar/noticebar.taro.tsx (4 hunks)
  • src/packages/noticebar/noticebar.tsx (4 hunks)
  • src/packages/popup/popup.taro.tsx (1 hunks)
  • src/packages/popup/popup.tsx (1 hunks)
  • src/packages/price/price.taro.tsx (1 hunks)
  • src/packages/price/price.tsx (1 hunks)
  • src/packages/progress/progress.taro.tsx (1 hunks)
  • src/packages/progress/progress.tsx (1 hunks)
  • src/packages/radio/radio.taro.tsx (1 hunks)
  • src/packages/radio/radio.tsx (1 hunks)
  • src/packages/swiper/demo.taro.tsx (4 hunks)
  • src/packages/swiper/demos/taro/demo10.tsx (1 hunks)
  • src/packages/swiper/effects/default.tsx (3 hunks)
  • src/packages/swiper/effects/focus.tsx (1 hunks)
  • src/packages/swiper/swiper.taro.tsx (2 hunks)
  • src/packages/swiper/swiper.tsx (2 hunks)
  • src/packages/switch/switch.taro.tsx (1 hunks)
  • src/packages/switch/switch.tsx (1 hunks)
  • src/packages/tabbar/demo.taro.tsx (5 hunks)
  • src/packages/tabbar/demo.tsx (5 hunks)
  • src/packages/tabbar/demos/h5/demo10.tsx (1 hunks)
  • src/packages/tabbar/demos/taro/demo10.tsx (1 hunks)
  • src/packages/tabbaritem/tabbaritem.taro.tsx (1 hunks)
  • src/packages/tabbaritem/tabbaritem.tsx (2 hunks)
  • src/packages/tabs/tabs.taro.tsx (3 hunks)
  • src/packages/tabs/tabs.tsx (3 hunks)
  • src/packages/toast/Notification.tsx (1 hunks)
  • src/packages/toast/toast.taro.tsx (1 hunks)
  • src/sites/components/header.tsx (1 hunks)
  • src/types/spec/countdown/base.ts (1 hunks)
  • src/types/spec/dialog/base.ts (1 hunks)
  • src/types/spec/dialog/taro.ts (1 hunks)
  • src/types/spec/image/base.ts (1 hunks)
  • src/types/spec/noticebar/base.ts (1 hunks)
  • src/types/spec/popup/base.ts (1 hunks)
  • src/types/spec/progress/base.ts (1 hunks)
  • src/types/spec/radio/base.ts (2 hunks)
  • src/types/spec/swiper/taro.ts (1 hunks)
  • src/types/spec/tabbar/base.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: oasis-cloud
Repo: jdf2e/nutui-react PR: 2700
File: src/packages/animatingnumbers/animatingnumbers.harmony.css:25-32
Timestamp: 2024-11-06T05:56:06.800Z
Learning: 在优化 NutUI React 动画性能时,添加 `will-change` 属性可能会对布局产生影响,需要谨慎使用。
📚 Learning: 2024-11-06T05:56:06.800Z
Learnt from: oasis-cloud
Repo: jdf2e/nutui-react PR: 2700
File: src/packages/animatingnumbers/animatingnumbers.harmony.css:25-32
Timestamp: 2024-11-06T05:56:06.800Z
Learning: 在优化 NutUI React 动画性能时,添加 `will-change` 属性可能会对布局产生影响,需要谨慎使用。

Applied to files:

  • src/packages/noticebar/demos/h5/demo12.tsx
  • src/packages/noticebar/demos/taro/demo12.tsx
📚 Learning: 2024-07-05T02:58:57.992Z
Learnt from: Alex-huxiyang
Repo: jdf2e/nutui-react PR: 2416
File: src/packages/uploader/uploader.taro.tsx:230-230
Timestamp: 2024-07-05T02:58:57.992Z
Learning: When changes are made to the `fileList` state in the `src/packages/uploader/uploader.taro.tsx` file, ensure to generate unit tests to cover these changes.

Applied to files:

  • src/packages/checkbox/checkbox.taro.tsx
📚 Learning: 2025-05-02T01:45:09.576Z
Learnt from: irisSong
Repo: jdf2e/nutui-react PR: 3209
File: src/packages/searchbar/searchbar.taro.tsx:111-124
Timestamp: 2025-05-02T01:45:09.576Z
Learning: 在 React/Taro 组件中使用 setTimeout 或 setInterval 时,应当在组件卸载时通过 useEffect 的清理函数清除定时器,以防止内存泄漏。可以使用 useState 存储定时器 ID,并在 useEffect 的返回函数中清除。

Applied to files:

  • src/packages/countdown/demos/h5/demo10.tsx
  • src/packages/countdown/demos/taro/demo10.tsx
  • src/packages/navbar/demos/taro/demo4.tsx
  • src/packages/countdown/countdown.taro.tsx
🧬 Code graph analysis (14)
src/packages/swiper/effects/focus.tsx (1)
src/hooks/use-ref-state.ts (1)
  • getRefValue (3-5)
src/packages/noticebar/demos/h5/demo12.tsx (3)
src/packages/noticebar/noticebar.taro.tsx (1)
  • NoticeBar (35-556)
src/packages/noticebar/noticebar.tsx (1)
  • NoticeBar (35-551)
src/packages/button/button.taro.tsx (1)
  • Button (63-182)
src/packages/radio/radio.taro.tsx (1)
src/packages/sidebar/utils.ts (1)
  • handleClick (22-22)
src/packages/tabbar/demos/taro/demo10.tsx (2)
src/packages/tabbar/demos/h5/demo9.tsx (1)
  • Tabbar (5-13)
src/packages/tabbar/demos/h5/demo5.tsx (1)
  • Tabbar (5-13)
src/packages/countdown/demo.tsx (1)
scripts/create-properties.js (1)
  • h2 (58-58)
src/packages/countdown/demos/h5/demo10.tsx (2)
src/packages/countdown/countdown.taro.tsx (1)
  • CountDown (355-357)
src/packages/countdown/countdown.tsx (1)
  • CountDown (308-310)
src/packages/countdown/demos/taro/demo10.tsx (2)
src/packages/countdown/countdown.taro.tsx (1)
  • CountDown (355-357)
src/packages/countdown/countdown.tsx (1)
  • CountDown (308-310)
src/types/spec/swiper/taro.ts (1)
src/types/spec/swiper/base.ts (1)
  • BaseSwiperItem (33-35)
src/packages/navbar/demos/h5/demo4.tsx (3)
src/packages/navbar/navbar.taro.tsx (1)
  • NavBar (19-138)
src/packages/navbar/navbar.tsx (1)
  • NavBar (18-137)
src/packages/toast/toast.taro.tsx (1)
  • Toast (39-194)
src/packages/navbar/demos/taro/demo4.tsx (3)
src/utils/taro/px-transform.ts (1)
  • pxTransform (5-9)
src/packages/navbar/navbar.taro.tsx (1)
  • NavBar (19-138)
src/utils/taro/platform.ts (1)
  • harmony (3-7)
src/packages/noticebar/demos/taro/demo12.tsx (2)
src/packages/noticebar/noticebar.taro.tsx (1)
  • NoticeBar (35-556)
src/packages/button/button.taro.tsx (1)
  • Button (63-182)
src/packages/image/demos/h5/demo9.tsx (2)
src/packages/image/image.taro.tsx (1)
  • Image (25-141)
src/packages/image/image.tsx (1)
  • Image (27-204)
src/packages/image/demos/taro/demo9.tsx (1)
src/packages/image/image.taro.tsx (1)
  • Image (25-141)
src/packages/swiper/demos/taro/demo10.tsx (3)
packages/nutui-inject-ui-styles/dist/index.js (1)
  • list (26-129)
src/packages/swiper/swiper.taro.tsx (1)
  • Swiper (31-179)
src/packages/image/image.taro.tsx (1)
  • Image (25-141)
🪛 ast-grep (0.39.7)
src/packages/countdown/countdown.tsx

[warning] 298-298: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

🔇 Additional comments (43)
src/types/spec/popup/base.ts (1)

20-20: 此更改似乎与 PR 目标不符。

此 PR 的目标是添加无障碍功能支持,但 top?: ReactNode 属性似乎是一个 UI 布局属性,而非无障碍相关的属性。请确认:

  1. 此更改是否应该包含在本 PR 中
  2. 或者应该在单独的 PR 中处理布局功能增强
src/packages/navbar/navbar.taro.tsx (1)

110-110: LGTM - 导航角色设置正确

ariaRole="navigation" 正确使用了 ARIA 地标角色,有助于屏幕阅读器用户快速导航到页面的导航区域。

src/types/spec/dialog/taro.ts (1)

6-7: LGTM - 类型定义正确

为 TaroContentProps 添加 ariaModal 和 ariaRole 属性的类型定义是正确的,这些属性将帮助对话框组件正确实现 ARIA 规范中的模态对话框语义。

src/packages/tabs/tabs.tsx (1)

185-186: LGTM - 正确隐藏装饰性元素

在视觉装饰元素(活动线指示器和笑脸图标)上使用 aria-hidden 是正确的做法,这可以防止屏幕阅读器读取这些仅用于视觉呈现的元素。

Also applies to: 189-192

src/packages/navbar/navbar.tsx (1)

109-109: LGTM - 导航角色设置正确

role="navigation" 正确使用了 ARIA 地标角色,有助于屏幕阅读器用户识别和导航到导航区域。

src/packages/tabs/tabs.taro.tsx (2)

266-269: 验证 ariaHidden 属性语法

与上面的问题相同,建议为 ariaHidden 明确设置布尔值。
[request_optional_refactor]

-                      <View
-                        className={`${classPrefix}-titles-item-smile`}
-                        ariaHidden
-                      >
+                      <View
+                        className={`${classPrefix}-titles-item-smile`}
+                        ariaHidden={true}
+                      >

281-284: ARIA 标签页属性实现正确

ariaRole="tab" 和 ariaSelected 的实现符合 WAI-ARIA 规范,正确反映了标签页的选中状态。

src/packages/progress/progress.taro.tsx (1)

225-226: 进度条无障碍属性实现正确

正确添加了 ariaLabel 和 ariaRole="progressbar" 属性,为屏幕阅读器提供了清晰的进度信息。默认的中文标签 "进度${percent}%" 对于中文用户友好。

src/packages/progress/progress.tsx (1)

138-139: Web 版本无障碍属性实现正确

使用标准的 React ARIA 属性 aria-label 和 role="progressbar",与 Taro 版本保持一致。

src/packages/popup/popup.tsx (1)

292-292: 弹窗角色属性正确

为弹窗容器添加 role="dialog" 符合 WAI-ARIA 规范,有助于屏幕阅读器正确识别弹窗的语义。

src/packages/countdown/countdown.tsx (2)

65-67: ARIA 提醒状态管理

添加状态来管理 ARIA 提醒的角色和内容是合理的。


105-110: 倒计时结束提醒逻辑

在倒计时结束时设置 ARIA 提醒,3秒后清除,这个交互逻辑合理。

src/packages/countdown/demo.tsx (1)

12-12: 代码更改看起来不错

Demo10 的导入和 ARIA 基础用法示例集成正确,多语言翻译键(zh-CN、zh-TW、en-US)都已正确添加。

Also applies to: 26-26, 38-38, 50-50, 75-76

src/packages/swiper/demo.taro.tsx (1)

17-17: 代码更改看起来不错

Demo10 的导入和 ARIA 示例集成正确,多语言翻译已正确添加。

Also applies to: 31-31, 43-43, 84-85

src/packages/navbar/demo.taro.tsx (1)

10-10: 代码更改看起来不错

Demo4 的导入和 ARIA 基础用法示例集成正确,多语言翻译键已完整添加。

Also applies to: 18-18, 24-24, 30-30, 45-46

src/packages/navbar/demo.tsx (1)

7-7: 代码更改看起来不错

Demo4 的导入和 ARIA 基础用法示例集成正确,多语言翻译已完整添加。

Also applies to: 15-15, 21-21, 27-27, 39-40

src/packages/noticebar/demo.tsx (1)

15-15: LGTM! ARIA 演示添加正确

Demo12 的导入、翻译键和渲染逻辑都符合现有的演示模式,实现正确。

Also applies to: 31-31, 45-45, 78-79

src/packages/noticebar/demo.taro.tsx (1)

19-19: LGTM! Taro 版本的 ARIA 演示添加正确

与 H5 版本保持一致,Demo12 的集成符合现有模式。

Also applies to: 35-35, 49-49, 88-89

src/packages/image/image.taro.tsx (1)

38-38: LGTM! ariaLabel 属性传递正确

正确地从 props 中解构 ariaLabel 并传递给底层的 TImage 组件,实现了无障碍标签支持。

Also applies to: 133-133

src/packages/tabbar/demo.tsx (1)

12-12: LGTM! Demo10 集成正确

ARIA 演示的导入、翻译(除 zh-TW 的小问题外)和渲染逻辑都实现正确。

Also applies to: 26-26, 50-50, 73-74

src/types/spec/noticebar/base.ts (1)

26-26: rightIconAriaLabel 属性定义不会造成破坏性变更

虽然 rightIconAriaLabel: string 在接口中被定义为必需属性,但实际并不会导致现有代码失败。组件的类型签名使用了 Partial<WebNoticeBarProps>,这使得所有属性在组件层面都是可选的。此外,组件提供了默认值 rightIconAriaLabel: ''。现有演示代码(如 demo1.tsx)已经在不提供此属性的情况下成功运行。

将其改为可选属性仍是更好的做法,以保持接口定义与实现的一致性,但这不是必要的修复。

Likely an incorrect or invalid review comment.

src/packages/countdown/demo.taro.tsx (1)

15-15: LGTM!

Demo10 组件导入和 ARIA 国际化配置实现正确,遵循了项目的标准 demo 集成模式。

Also applies to: 29-29, 41-41, 53-53, 83-84

src/packages/swiper/swiper.tsx (1)

41-41: LGTM!

alt 属性的提取和转发实现正确,当未指定 effect 时,该属性会正确传递给 defaultEffect 用于设置 ARIA 标签。

Also applies to: 256-263

src/packages/image/image.tsx (1)

45-45: LGTM!

ariaLabel 属性的实现符合无障碍规范,正确应用于 img 元素的 aria-label 属性。

Also applies to: 198-198

src/types/spec/dialog/base.ts (1)

45-45: LGTM!

为 BaseDialog 接口添加 role 属性的类型定义,与无障碍功能增强保持一致。

src/packages/tabbar/demos/taro/demo10.tsx (1)

5-38: LGTM!

Demo 正确演示了 ARIA 属性的使用方式,为每个 Tabbar.Item 提供了 ariaLabel 和 ariaRoledescription 属性,有助于改善屏幕阅读器的用户体验。

src/packages/dialog/dialog.tsx (1)

221-221: LGTM!

为 Dialog 组件添加的 ARIA 属性实现正确:

  • role="dialog" 正确标识了对话框角色
  • aria-modal={visible} 在对话框可见时正确设置模态状态

这些改动提升了对话框组件的无障碍性。

Also applies to: 230-230

src/packages/countdown/demos/taro/demo10.tsx (2)

1-10: LGTM!

导入和组件初始化代码正确,使用 useRef 存储 endTime 是合适的做法。


11-38: 演示代码清晰有效

三个 CountDown 实例展示了不同的 type 属性,同时统一使用了 ariaRoledescription 属性,有效演示了无障碍功能的使用。

src/packages/image/demos/h5/demo9.tsx (2)

16-23: LGTM!

正确使用了 alt 和 ariaLabel 属性,alt 描述图片内容,ariaLabel 提供可访问的名称,这是符合无障碍最佳实践的。


24-40: 错误处理演示清晰

使用无效 URL 触发错误状态是演示错误处理功能的常见做法,同时展示了默认和自定义错误内容两种场景。

src/packages/tabbar/demo.taro.tsx (1)

15-15: Demo10 集成正确

Demo10 的导入和渲染遵循了现有的演示模式,集成方式正确。

Also applies to: 78-79

src/packages/dialog/content.taro.tsx (1)

31-32: ARIA 属性集成正确

ariaRole 和 ariaModal 属性的添加和使用符合 Taro 的无障碍实现模式,将 ariaModal 绑定到 visible 状态也是合理的。

Also applies to: 64-65

src/packages/countdown/demos/h5/demo10.tsx (1)

11-38: 演示结构实现正确

三个 CountDown 实例正确展示了不同 type 属性下的 ariaRoledescription 使用,演示结构清晰。

src/packages/tabbar/demos/h5/demo10.tsx (1)

7-37: ARIA 属性使用规范

每个 Tabbar.Item 都正确配置了 ariaLabel 和 ariaRoledescription 属性,ariaLabel 与 title 保持一致,ariaRoledescription 统一描述了操作类型,符合无障碍最佳实践。动态图标的使用也展示了更丰富的交互场景。

src/packages/noticebar/demos/taro/demo12.tsx (2)

20-26: rightIconAriaLabel 使用正确

为右侧图标添加 rightIconAriaLabel="more" 提供了可访问的标签,这对于屏幕阅读器用户理解图标功能很重要。


28-39: 自定义右侧内容演示清晰

使用 right 插槽放置自定义 Button 组件展示了 NoticeBar 的灵活性,虽然这个示例不直接涉及无障碍功能,但与其他演示一起提供了完整的使用场景。

src/packages/dialog/content.tsx (1)

57-64: ARIA 属性实现正确

role 和 aria-modal 属性的实现符合无障碍规范。role 属性被正确传递,aria-modal 接收布尔值以反映对话框的模态状态。

src/packages/noticebar/noticebar.taro.tsx (1)

543-551: 验证 rightIconAriaLabel 为空的情况

当 closeable 为 false 且用户未提供 rightIconAriaLabel 时,aria-label 将是空字符串,这对屏幕阅读器用户没有帮助。虽然通常在有 rightIcon 时应该提供有意义的 rightIconAriaLabel,但建议在文档中明确说明这一要求,或者在代码中添加条件判断,仅在有有效内容时才设置 aria-label。

建议验证以下场景:

  1. 当使用 rightIcon 但未提供 rightIconAriaLabel 时的行为
  2. 文档是否明确要求提供 rightIconAriaLabel

可以考虑改进实现:

ariaLabel={closeable ? 'close' : (rightIconAriaLabel || undefined)}

这样当 rightIconAriaLabel 为空时,不会设置 aria-label 属性。

src/packages/noticebar/noticebar.tsx (1)

481-487: 验证 rightIconAriaLabel 为空的情况

与 Taro 版本类似,当 closeable 为 false 且 rightIconAriaLabel 为空时,aria-label 将是空字符串。建议确保文档中明确要求在使用自定义 rightIcon 时必须提供有意义的 rightIconAriaLabel。

可选改进(与 Taro 版本保持一致):

           <div
             className="nut-noticebar-box-right-icon"
             onClick={onClickIcon}
-            aria-label={`${closeable ? 'close' : rightIconAriaLabel}`}
+            aria-label={closeable ? 'close' : (rightIconAriaLabel || undefined)}
           >
src/packages/dialog/dialog.taro.tsx (1)

234-259: ARIA 实现正确且完善

Dialog 组件的无障碍实现非常完善:

  • 正确传递 role 属性到 Content 组件
  • ariaModal 属性正确反映对话框的模态状态
  • 为 Overlay 添加了有意义的 ariaRoledescription="背景蒙层",帮助屏幕阅读器用户理解背景遮罩的用途
src/packages/navbar/demos/h5/demo4.tsx (1)

1-95: 优秀的无障碍示例

这个 Demo 很好地展示了 NavBar 的无障碍用法:

  • 所有交互元素都添加了有意义的 aria-label
  • 标签描述清晰准确
  • 为开发者提供了良好的参考示例
src/packages/countdown/countdown.taro.tsx (1)

341-348: ARIA alert 实现正确

倒计时结束时的 ARIA alert 实现遵循了无障碍最佳实践:

  • 使用 role="alert" 动态通知屏幕阅读器
  • 提供有意义的提示内容 "时间到"
  • 通过隐藏的元素实现,不影响视觉布局

注意:已在上方评论中指出定时器清理的问题。

Comment thread src/packages/button/button.taro.tsx Outdated
className={buttonClassNames}
style={{ ...getStyle, ...style }}
onClick={(e) => handleClick(e as any)}
ariaLabel="button"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

硬编码的 ariaLabel 值缺乏实用性。

将 ariaLabel 硬编码为 "button" 不会为屏幕阅读器用户提供有意义的信息。应该:

  1. 通过 props 使其可配置
  2. 描述按钮的具体用途而非仅说明它是按钮
  3. 设为可选属性,因为按钮内容通常已提供足够的上下文

建议应用以下修改:

在 ButtonProps 接口中添加可选的 ariaLabel 属性:

 export interface ButtonProps
   extends BasicComponent,
     OmitMiniProgramButtonProps {
   color: string
   shape: ButtonShape
   type: ButtonType
   size: ButtonSize
   fill: ButtonFill
   block: boolean
   loading: boolean
   disabled: boolean
   icon: React.ReactNode
   rightIcon: React.ReactNode
   nativeType: 'submit' | 'reset' // | 'button'
   onClick: (e: MouseEvent<HTMLButtonElement>) => void
+  ariaLabel?: string
 }

然后在组件中使用:

 const {
   color,
   shape,
   fill,
   loading,
   disabled,
   type,
   size,
   block,
   icon,
   rightIcon,
   children,
   className,
   style,
   formType,
   nativeType,
   onClick,
+  ariaLabel,
   ...rest
 } = { ...defaultProps, ...props }

在渲染时有条件地应用:

 <TaroButton
   {...rest}
   ref={ref}
   formType={formType || nativeType}
   className={buttonClassNames}
   style={{ ...getStyle, ...style }}
   onClick={(e) => handleClick(e as any)}
-  ariaLabel="button"
+  {...(ariaLabel && { ariaLabel })}
 >

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/packages/button/button.taro.tsx around line 162, the ariaLabel is
hardcoded to "button"; update ButtonProps to include an optional ariaLabel?:
string, accept it in the component props, and replace the hardcoded ariaLabel
with the passed-in prop so the rendered element conditionally sets the
aria-label attribute only when ariaLabel is provided (or uses a meaningful
fallback like the button text if you choose), ensuring the value describes the
button's purpose rather than the generic word "button".

Comment thread src/packages/checkbox/checkbox.tsx Outdated
Comment on lines +211 to +213
role="checkbox"
tabIndex={0}
aria-checked={innerChecked && !innerIndeterminate}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

aria-checked 对不确定状态的处理不正确。

当前的 aria-checked={innerChecked && !innerIndeterminate} 实现存在严重问题:

  1. 不确定状态处理错误:当复选框处于不确定状态(indeterminate=true)时,aria-checked 应该是 "mixed",而不是 false
  2. 类型不正确:aria-checked 应该接受 "true" | "false" | "mixed",而非布尔运算结果
  3. tabIndex 未考虑禁用状态:禁用的复选框不应该可聚焦

应用以下修改:

 <div
   className={classNames(
     classPrefix,
     {
       [`${classPrefix}-reverse`]: labelPosition === 'left',
       'nut-checkbox-list-item': ctx?.list,
     },
     className
   )}
   {...rest}
   onClick={handleClick}
   role="checkbox"
-  tabIndex={0}
-  aria-checked={innerChecked && !innerIndeterminate}
+  tabIndex={innerDisabled ? -1 : 0}
+  aria-checked={innerIndeterminate ? 'mixed' : innerChecked}
 >
   {renderCheckboxItem()}
 </div>

此外,建议添加键盘事件处理器以支持空格键切换复选框:

+const handleKeyDown = (e: React.KeyboardEvent) => {
+  if (e.key === ' ' || e.key === 'Enter') {
+    e.preventDefault()
+    handleClick()
+  }
+}
+
 <div
   className={classNames(
     classPrefix,
     {
       [`${classPrefix}-reverse`]: labelPosition === 'left',
       'nut-checkbox-list-item': ctx?.list,
     },
     className
   )}
   {...rest}
   onClick={handleClick}
+  onKeyDown={handleKeyDown}
   role="checkbox"
   tabIndex={innerDisabled ? -1 : 0}
   aria-checked={innerIndeterminate ? 'mixed' : innerChecked}
 >

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/packages/checkbox/checkbox.tsx around lines 211-213, aria-checked and
tabIndex are incorrect: change aria-checked to return the string union "true" |
"false" | "mixed" (e.g. innerIndeterminate ? "mixed" : innerChecked ? "true" :
"false") instead of a boolean expression, make tabIndex non-focusable when
disabled (e.g. tabIndex={disabled ? -1 : 0}), and add a onKeyDown handler that
listens for the Space key, prevents default, and toggles the checkbox
(respecting disabled state) so keyboard users can toggle via space.

Comment on lines +110 to +115
setRole('alert')
setAlertContent('时间到')
setTimeout(() => {
setRole('')
setAlertContent('')
}, 3000)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

修复潜在的内存泄漏

setTimeout 设置的定时器在组件卸载时未被清除,可能导致内存泄漏。当倒计时结束后,如果组件在 3 秒内被卸载,定时器仍会尝试调用 setRole 和 setAlertContent,可能导致 React 警告或内存泄漏。

基于学习经验(Based on learnings)

建议将定时器 ID 存储在 ref 中并在组件卸载时清除:

+  const alertTimerRef = useRef<number>()
+
   // ... 在 tick 函数中
         if (!remainTime) {
           stateRef.current.counting = false
           pause()
           onEnd && onEnd()
           setRole('alert')
           setAlertContent('时间到')
-          setTimeout(() => {
+          alertTimerRef.current = window.setTimeout(() => {
             setRole('')
             setAlertContent('')
           }, 3000)
         }

并在 componentWillUnmount 中清除:

   const componentWillUnmount = () => {
     destroy && cancelAnimationFrame(stateRef.current.timer)
+    if (alertTimerRef.current) {
+      clearTimeout(alertTimerRef.current)
+    }
   }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/packages/countdown/countdown.taro.tsx around lines 110 to 115, the
setTimeout used to clear role/alertContent is not tracked or cleared on unmount
which can cause state updates after unmount; store the timeout ID in a ref (e.g.
timeoutRef), assign the ID when calling setTimeout, clear any existing timeout
before creating a new one, and clear the timeout in useEffect
cleanup/componentWillUnmount to prevent the callback running after the component
is unmounted.

Comment thread src/packages/countdown/demos/h5/demo10.tsx
Comment thread src/packages/image/demo.taro.tsx Outdated
error: '加载失败',
lazyload: '图片懒加载',
imageText: 'Image + text 模式',
ATRIAUsage: '无障碍使用示例',

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

修正拼写错误:ATRIA → ARIA

翻译键名和英文翻译值中的 "ATRIA" 是拼写错误,应该是 "ARIA"(Accessible Rich Internet Applications,无障碍富互联网应用)。

应用此差异修复拼写错误:

-      ATRIAUsage: '无障碍使用示例',
+      ARIAUsage: '无障碍使用示例',
-      ATRIAUsage: 'ATRIA Usage',
+      ARIAUsage: 'ARIA Usage',

同时需要更新 Line 70 的引用:

-        <View className="h2">{translated.ATRIAUsage}</View>
+        <View className="h2">{translated.ARIAUsage}</View>

Also applies to: 39-39

🤖 Prompt for AI Agents
In src/packages/image/demo.taro.tsx around lines 28 and 39 (and update the usage
at line 70), fix the misspelling "ATRIA" to "ARIA": rename the translation
key(s) (e.g., ATRIAUsage → ARIAUsage), update any English/Chinese translation
values that contain "ATRIA" to "ARIA", and change the reference at line 70 to
use the new ARIAUsage key; ensure consistency across the file so all occurrences
of "ATRIA" are replaced with "ARIA".

Comment thread src/types/spec/radio/base.ts Outdated
activeIcon: ReactNode
value: SimpleValue
onChange: (checked: boolean) => void
type: string

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

属性名称 "type" 过于泛化且可能引起混淆。

在 BaseRadio 接口中添加 type: string 存在以下问题:

  1. 属性名称过于通用,不清楚其用途
  2. 可能与 HTML 原生的 type 属性产生命名冲突
  3. 如果用于无障碍功能,应使用更具描述性的名称(如 ariaType 或 role)
  4. 应设为可选属性而非必需

请说明此属性的具体用途,并考虑使用更具描述性的名称。

🤖 Prompt for AI Agents
In src/types/spec/radio/base.ts around line 24, the BaseRadio interface defines
a generic required property "type: string" which is ambiguous and could clash
with HTML attributes; clarify its purpose and either rename it to a descriptive
name (e.g., "variant", "role", or "ariaType") or make it optional if it conveys
non-essential metadata. Update the interface to use the new name or optional
modifier, adjust all imports/usages and tests to the new property, and add a
short JSDoc comment explaining the property's semantics and expected values to
avoid future confusion.

Comment thread src/types/spec/radio/base.ts Outdated
disabled?: boolean
options: RadioGroupOption[]
onChange: (value: SimpleValue) => void
type: string

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

属性名称 "type" 过于泛化且可能引起混淆。

在 BaseRadioGroup 接口中添加 type: string 存在与 BaseRadio 相同的问题。建议:

  1. 使用更具描述性的属性名称
  2. 将其设为可选属性
  3. 在文档中明确说明其用途
🤖 Prompt for AI Agents
In src/types/spec/radio/base.ts around line 36, the property named "type:
string" is too generic and may conflict with BaseRadio; rename it to a more
descriptive identifier (for example radioType or variant), make the property
optional (radioType?: string) and update any usages/imports accordingly, and add
a short JSDoc comment above the property explaining its purpose and expected
values; ensure type references, interfaces and any serializers/deserializers are
updated to use the new optional name to avoid breaking changes.

Comment thread src/types/spec/swiper/taro.ts Outdated
autoplay: boolean
loop: boolean
defaultValue: number
ariaLabel: string

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

ariaLabel 应设为可选属性。

将 ariaLabel 定义为必需属性会强制所有 Swiper 实例都必须提供 aria 标签。建议设为可选,因为:

  1. 组件可以提供合理的默认标签
  2. 并非所有使用场景都需要自定义标签
  3. 减少开发者的使用负担

应用以下修改:

 export type TaroSwiperProps = Omit<BaseSwiper, OmittedKeys> &
   OmittedSwiperProps &
   BaseProps & {
     width?: SimpleValue
     height?: SimpleValue
     direction: Direction
     indicator: ReactNode
     /**
      * @deprecated Please use `autoplay` prop instead.
      */
     autoPlay: boolean
     autoplay: boolean
     loop: boolean
     defaultValue: number
-    ariaLabel: string
+    ariaLabel?: string
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ariaLabel: string
export type TaroSwiperProps = Omit<BaseSwiper, OmittedKeys> &
OmittedSwiperProps &
BaseProps & {
width?: SimpleValue
height?: SimpleValue
direction: Direction
indicator: ReactNode
/**
* @deprecated Please use `autoplay` prop instead.
*/
autoPlay: boolean
autoplay: boolean
loop: boolean
defaultValue: number
ariaLabel?: string
}
🤖 Prompt for AI Agents
In src/types/spec/swiper/taro.ts around line 22, the ariaLabel property is
currently defined as a required string which forces all Swiper instances to
supply an ARIA label; change the type to make ariaLabel optional (e.g., use
optional property syntax) so the component can rely on a default or omit it when
not needed, and update any related type usages or overrides that assume it is
always present to handle undefined.

Comment thread src/types/spec/swiper/taro.ts Outdated
export interface TaroSwiperItemProps extends Omit<BaseSwiperItem, 'onClick'> {
itemId?: string
skipHiddenItemLayout?: boolean
ariaLabel: string

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

ariaLabel 应设为可选属性。

与 TaroSwiperProps 相同,TaroSwiperItemProps 的 ariaLabel 也应设为可选属性。

应用以下修改:

 export interface TaroSwiperItemProps extends Omit<BaseSwiperItem, 'onClick'> {
   itemId?: string
   skipHiddenItemLayout?: boolean
-  ariaLabel: string
+  ariaLabel?: string
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ariaLabel: string
export interface TaroSwiperItemProps extends Omit<BaseSwiperItem, 'onClick'> {
itemId?: string
skipHiddenItemLayout?: boolean
ariaLabel?: string
}
🤖 Prompt for AI Agents
In src/types/spec/swiper/taro.ts around line 28, the property ariaLabel is
currently required; make it optional to match TaroSwiperProps by changing its
declaration to an optional property (ariaLabel?: string) so TaroSwiperItemProps
aligns with the other prop definitions.

Comment thread src/types/spec/tabbar/base.ts Outdated
Comment on lines +25 to +27
ariaLabel: string
ariaSelected: boolean
ariaRoledescription: string

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

建议将 ARIA 属性设为可选

这些 ARIA 属性被定义为必需属性,这会导致所有现有的 TabbarItem 使用处都需要提供这些值,可能造成破坏性变更。建议将它们设为可选属性以保持向后兼容。

应用此差异将属性改为可选:

-  ariaLabel: string
-  ariaSelected: boolean
-  ariaRoledescription: string
+  ariaLabel?: string
+  ariaSelected?: boolean
+  ariaRoledescription?: string
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ariaLabel: string
ariaSelected: boolean
ariaRoledescription: string
ariaLabel?: string
ariaSelected?: boolean
ariaRoledescription?: string
🤖 Prompt for AI Agents
In src/types/spec/tabbar/base.ts around lines 25 to 27, the ARIA properties
ariaLabel, ariaSelected and ariaRoledescription are currently required; change
their type declarations to optional (e.g., add ? after each property name) so
existing TabbarItem usages aren’t broken, update any related exported
interfaces/types if necessary, and run type checks to ensure no downstream type
errors remain.

@yangyanAurora
yangyanAurora marked this pull request as draft November 10, 2025 07:38
yangyanAurora and others added 4 commits November 10, 2025 18:35
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@yangyanAurora yangyanAurora changed the title feat: 添加部分组件无障碍功能支持 feat: 添加组件无障碍功能支持 Nov 10, 2025
yangyanAurora and others added 8 commits November 10, 2025 20:56
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
yangyanAurora and others added 10 commits November 12, 2025 16:43
* fix: fix showCount props is invalid in alipay (jdf2e#3366)

* feat: 添加部分组件无障碍功能支持
- button
- Checkbox
- Countdown
- Empty
- Image
- InputNumber
- Price
- Progress
- NavBar
- NoticeBar
- Radio
- Switch
- Tabbar
- Tabs
- Toast

* Revert "feat: 添加部分组件无障碍功能支持"

This reverts commit 2e7cbd2.

* feat: 添加组件无障碍功能支持

- button
- Checkbox
- Popup
- Dialog
- Overlay
- Radio
- Switch
- Toast

* fix: update

* fix: update

* fix: update

* fix: update Overlay

---------

Co-authored-by: ryanwang <email@binlin.wang>
- Image
- Countdown
- InputNumber
- NavBar
- NoticeBar
- Price
- Progress
- Tabbar
- Tabs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

3.x Target branch 3.x action:review This PR needs more reviews (less than 2 approvals) size/XXL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants