Prompts-MCP 686 skills · ai / design / design-pattern / framework / fundamentals / habit / lang / tech-selection /mcp/sse
framework framework/react/a11y/semantic-and-aria.md medium

react-a11y-semantic-and-aria

React 语义 HTML 与 ARIA 约定:优先原生语义元素,ARIA 仅补缺。Use when 选语义标签 / 给自研控件补 role 与状态 / 关联 label 与表单控件 / 图标按钮加无障碍名

语义 htmlariarolearia-labelaria-pressedaria-livelabel htmlfor表单关联图标按钮装饰图 alt
paths
  • frontend/src/**/*.tsx
  • frontend/src/**/*.ts

React · 语义 HTML 与 ARIA

规则

决策点:能用原生语义元素就别上 ARIA。no ARIA 好过 bad ARIA —— 错的 role 比没有更伤可达性。

场景 首选 补什么
点击操作 <button> 无;自带 role/键盘
导航 / 主内容 / 列表 <nav>/<main>/<ul><li> 无;自带地标语义
自研 toggle(非原生 input) <button> role 视情况 + aria-pressed={on}
自研 tablist 容器 role="tablist" / 项 role="tab" aria-selected
图标按钮(无可见文字) <button> aria-label="删除"
装饰性图片 <img> alt=""(空串,读屏跳过)
动态更新区(轮询/异步结果) 区域容器 aria-live="polite"

表单 label 关联:<label htmlFor={id}> 显式绑,或 <label> 直接包裹控件。antd Form.Item label 自动处理关联,无需手写;自研 input 必须显式 htmlFor+id

antd 多数组件(Button/Tabs/Menu/Modal)自带正确 role,直接用即可;自研壳层(见 when-antd-vs-custom)要自己补齐 role 与状态。

反例·正例

// 反例:div 当按钮 —— 无 role、无键盘、读屏读不出可点
const ToggleBad = ({ on, onToggle }: { on: boolean; onToggle: () => void }) => (
  <div className="toggle" onClick={onToggle}>{on ? "开" : "关"}</div>
);

// 反例:图标按钮无可访问名 —— 读屏只念出 "button"
const DeleteBad = ({ onDelete }: { onDelete: () => void }) => (
  <button onClick={onDelete}><DeleteOutlined /></button>
);
import { Button } from "antd";
import { DeleteOutlined } from "@ant-design/icons";

// 正例:自研 toggle 用 button,状态走 aria-pressed
const Toggle = ({ on, onToggle }: { on: boolean; onToggle: () => void }) => (
  // 原生 button 自带 role/键盘;aria-pressed 暴露开关态给读屏
  <button type="button" aria-pressed={on} onClick={onToggle}>
    {on ? "开" : "关"}
  </button>
);

// 正例:图标按钮补 aria-label 作可访问名
const DeleteButton = ({ onDelete }: { onDelete: () => void }) => (
  <Button aria-label="删除" icon={<DeleteOutlined />} onClick={onDelete} />
);

// 正例:自研 input 显式关联 label
const SearchField = ({ value, onChange }: { value: string; onChange: (v: string) => void }) => (
  <>
    <label htmlFor="kw">关键词</label>
    {/* htmlFor 与 input id 对齐,点 label 聚焦控件 */}
    <input id="kw" value={value} onChange={(e) => onChange(e.target.value)} />
  </>
);

自检

  • [ ] 可点元素是 <button>/<a> 而非 <div onClick>(自带 role 与键盘)?
  • [ ] 用了原生语义标签(nav/main/ul),没有为 div 硬贴 ARIA role?
  • [ ] 自研 toggle 暴露 aria-pressed、tab 暴露 aria-selected,状态随交互更新?
  • [ ] 纯图标按钮都有 aria-label?装饰图 alt=""
  • [ ] 表单控件都有关联 label(antd Form.Item label 或自研 htmlFor+id)?
  • [ ] 异步/轮询更新的区域包了 aria-live
  • [ ] 没有为偷懒补错的 role(no ARIA 好过 bad ARIA)?

相关