开发规范:EUI 组件的 ARIA、焦点管理与键盘交互最佳实践)
Kibana 无障碍Accessibility开发规范EUI 组件的 ARIA、焦点管理与键盘交互最佳实践【免费下载链接】kibanaYour window into all of your data项目地址: https://gitcode.com/GitHub_Trending/ki/kibana本文基于 Kibana 仓库内置的accessibility技能文档.agents/skills/accessibility/SKILL.md及其references/目录系统梳理 Kibana 前端开发中的无障碍写作规范从 WCAG 2.2 AA 标准与 APG 模式、可访问命名、国际化约束到 11 份 EUI 组件级指南EuiModal、EuiToolTip、EuiBasicTable、EuiFormRow等的规范写法再到elastic/euiESLint 规则到组件指南的映射与人工审查要点。读完本文后你能够在新写或重构 EUI 组件时遵循 Kibana 的“规范模式canonical pattern”并在遇到elastic/eui/*ESLint 报错时快速定位到对应组件指南完成修复。适用场景什么时候查阅这套无障碍规范技能文档 SKILL.md 开宗明义无障碍是写组件的一部分而不是 lint 报错之后才补的步骤Accessibility is part of writing the component, not a step that happens after lint complains。在编写 JSX 之前先打开对应组件指南并优先通读共享原则文档。该文档明确了三类使用场景编写或重构 EUI 组件从 组件指南总表 打开匹配的指南遵循规范模式props、可访问名称、焦点、ids修复elastic/eui/*ESLint 错误通过 ESLint 规则映射表从规则 id 跳转到解释规范修复方式的组件指南一般的无障碍问题或非 EUI 组件问题阅读 共享原则。当规则之间发生冲突时shared_principles.md 给出明确的优先级顺序任务特定的用户或系统指令共享原则文档本身组件指南components/*.md或 ESLint 映射表eslint.md。共享原则所有无障碍决策的基座references/shared_principles.md 对“写新代码”“重构”“修 lint 报错”三种情形一视同仁是各组件指南的公共基础。技术标准达到WCAG 2.2 AA控件widget交互模式遵循 WAI-ARIA Authoring Practices GuideAPG优先使用 EUI 组件而非原生 HTML——EUI 默认处理 aria 属性、焦点与键盘行为只有在没有合适 EUI 组件时才使用原生 HTML优先语义化 HTML 而非 ARIA——仅在原生语义不够时才补 ARIA。写作决策顺序Authoring decision order无论是新写组件还是修旧代码自上而下逐层尝试在第一个能解决问题的层级停止语义Semantics选对元素/EUI 组件并使用其内建 propslabel、htmlFor、aria-label、aria-labelledby、aria-describedby、roles结构接线Structural wiring通过稳定 ididaria-labelledby把可见文本与控件关联而不是把字符串复制进隐藏 label行为Behavior只有在语义已正确时才调整键盘/焦点行为生命周期 hack 兜底用useEffect处理焦点或播报是最后手段仅在不存在声明式替代方案时使用。可访问命名Accessible naming每个交互元素按钮、链接、输入框、下拉框、自定义控件都需要可访问名称优先用可见文本label、标题、按钮文字作为名称通过aria-labelledby 稳定 id 接线而不是复制成aria-label每个控件只使用一种命名机制——aria-label与aria-labelledby不可并用不要移除title、alt、aria-label、aria-labelledby除非用更强的替代方案替换传达语义的图片需要alt纯装饰图片用alt或aria-hiddentrue。国际化i18n约束用户可见字符串与辅助技术字符串aria-label、tableCaption、tooltip 的content、label、title、错误消息、正文必须走 i18n 本地化禁止裸字面量而程序性 tokenradio 的name、内部 id保持纯字符串即可。具体的 i18n API 与消息 id 约定遵循 Kibana 的 kibana-i18n 技能。文档还要求如果文件中已有共享对象如i18nTexts.modalTitle新增字符串应沿用该局部模式而不是追加内联的i18n.translate调用。HTML id 生成所有id/aria-labelledby/titleProps.id接线都应使用 EUI 的 id 生成器调用一次并保存到有描述性的变量如modalTitleId、fieldLabelId若已有 id 变量指向同一元素则直接复用。函数组件从elastic/eui导入useGeneratedHtmlId在第一个return之前调用import { useGeneratedHtmlId } from elastic/eui; const labelId useGeneratedHtmlId();类组件使用htmlIdGenerator在render()中配合稳定后缀调用import { htmlIdGenerator } from elastic/eui; render() { const labelId htmlIdGenerator()(myLabel); }键盘与焦点每个交互元素必须可仅凭键盘到达并操作优先使用原生可聚焦元素button、a、input避免divonClicktabIndex不得移除或隐藏可见的焦点指示器焦点顺序遵循逻辑阅读顺序模态框与 flyout 必须 trap 焦点并在关闭时把焦点还回触发元素自定义快捷键不得与浏览器/读屏器快捷键冲突。最小确定性变更、类型安全与升级时机文档同时规定了几条“工程纪律”最小变更应用契合规范模式的最小改动不做无关重构、不改动布局/逻辑/license 头同样的代码形态应产生同样的结果类型安全禁止放宽类型string→any或使用ts-ignore、as any压制错误新 props 必须匹配组件类型定义何时升级给人类审查{...props}展开导致无法追踪aria-labelledby/aria-label/name是否已被提供无可见标题且新增标题会改变 UX需要设计/PM 介入需求冲突例如加aria-label会与title重复但删title又破坏其他消费者或从上下文无法判断 label/caption 是否准确描述了元素用途变更边界不向改动行添加叙述性注释、不删除既有注释除非指南明确要求若测试断言因 DOM 变化而失败只更新该断言——绝不删除或跳过测试。组件指南总览components/index.md 以表格形式索引了 11 份组件指南每份指南都是共享原则的组件级延伸指南主题涉及 EUI 组件callouts.md条件出现时如何播报 CalloutEuiCallOutcopy_tooltip.md复制到剪贴板的 tooltipbeforeMessage禁止嵌套 tooltipEuiCopy、EuiToolTip、EuiButtonIcondata_tables.md数据表格captionEuiBasicTable、EuiInMemoryTablefocus_and_keyboard.md焦点与键盘tab 顺序、tooltip 锚点EuiButton、EuiButtonIcon、EuiLink、EuiToolTipform_layout.md表单行与无效状态EuiFormRow、EuiFieldText、EuiFieldNumber、EuiFilePicker、EuiComboBox、EuiTextArea、EuiSelecticons_and_tooltips.md图标与图标提示装饰性 vs 语义性EuiIcon、EuiIconTip、EuiToolTipinteractive_components.md交互控件的命名EuiBetaBadge、EuiButtonIcon、EuiComboBox、EuiSelect、EuiSuperSelect、EuiPagination、EuiTreeView、EuiBreadcrumbsoverlays.md模态框、flyout、popoverEuiModal、EuiFlyout、EuiFlyoutResizable、EuiConfirmModal、EuiPopoverradio_groups.mdRadio 分组nameEuiRadio、EuiRadioGrouptooltip_content.mdtooltipcontent/title中禁止交互元素EuiToolTip、EuiIconTiptooltip_icon.md图标按钮上的 tooltip包裹 避免读屏重复、禁用原生titleEuiToolTip、EuiButtonIcon下面选取其中信息量最大的几份指南展开说明。条件渲染的 EuiCallOutannounceOnMount与 live regioncallouts.md 指出的核心问题是条件出现的 callout校验结果、异步返回、提交后反馈对辅助技术而言是“隐形”的除非显式启用 EUI 的 live-region 行为。规范写法分三种情形条件渲染condition …、三元、分支、提前 return→ 设置announceOnMount让 callout 在挂载时被播报始终挂载的静态 callout→ 省略announceOnMount它不需要 live region条件渲染但明确不播报罕见→ 显式announceOnMount{false}并在不明显时在调用点注释原因。// 条件渲染正确 {hasError ( EuiCallOut announceOnMount title{i18n.translate(form.errorTitle, { defaultMessage: Error })} colordanger {errorMessage} /EuiCallOut )} // 显式退出 {decorativeCondition ( EuiCallOut announceOnMount{false} title… … /EuiCallOut )}常见错误条件 callout 忘了announceOnMount或在静态 callout 上多加了announceOnMount。若EuiCallOut通过{...calloutProps}展开且开始标签上没有announceOnMount应在调用点或 spread 源头合并该 prop。Kibana 仓库中已有真实用例可作参照例如 submit_error_callout.tsx 与 vega_data_inspector.tsx 都使用了announceOnMount。复制到剪贴板EuiCopy 自带 tooltip禁止嵌套copy_tooltip.md 的关键事实EuiCopy已经会把 render-prop 子元素包进EuiToolTip并把beforeMessage用作 tooltip 的content复制成功后切换为afterMessage。因此在 render prop 里再包一层自己的EuiToolTip会产生两个嵌套 tooltip 争抢同一锚点——hover/focus 行为不可预测读屏播报重复。规范要点在EuiCopy上设置本地化后的beforeMessage不要在 render prop 内添加EuiToolTiprender-prop 子元素仍需要自己的可访问名称——EuiButtonIcon保留aria-label或EuiButton使用可见文本。EuiCopy的 tooltip 提供的是可见提示不是可访问名称由于 tooltip 来自EuiCopyelastic/eui/tooltip-button-icon-wrap规则不会要求你再包一层存在EuiCopy例外但原生titleprop 依然被禁止若没有beforeMessage则 tooltip 根本不存在EuiToolTip对空 content 会自我抑制此时应按tooltip_icon.md正常包裹——或者更推荐补上beforeMessage。const copyLabel i18n.translate(myFeature.copyValue, { defaultMessage: Copy value, }); EuiCopy textToCopy{value} beforeMessage{copyLabel} {(copy) ( EuiButtonIcon onClick{copy} iconTypecopy aria-label{copyLabel} / )} /EuiCopy指南还列出了规则无法自动处理的情形beforeMessage来自变量或 JSX 时没有 autofix需人工决定保留哪段文案静态空值、{null}、{false}时no-nested-copy-tooltip保持沉默而tooltip-button-icon-wrap仍要求包裹render prop 的根元素若经由 helper 函数、变量或map产生则不被静态分析覆盖需自行检查。数据表格tableCaption不可缺省data_tables.md 要求EuiBasicTable/EuiInMemoryTable必须传递恰好一个tableCaption让辅助技术知道这张表代表什么数据集它不同于页面title。文案应描述数据集或任务如“User accounts in this space”而不是泛泛的 “Table”新字符串走i18n.translate若tableCaption经{...tableProps}提供应在源头修复合并绝不重复两个互相冲突的 caption。EuiBasicTable tableCaption{i18n.translate(usersList.tableCaption, { defaultMessage: User accounts list, })} items{items} columns{columns} /仓库中的实际用法可以参考 files_management/public/app.tsx 与 data_table.tsx它们都在表格上显式提供了tableCaption。焦点与键盘tabIndex 的两个极端focus_and_keyboard.md 针对EuiButton、EuiButtonIcon、EuiLink、EuiToolTip给出两条相反的规则恰好构成tabIndex的完整心智模型内置交互 EUI 控件自动参与顺序焦点导航WCAG 2.1.1永远不要对它们设置tabIndex{-1}条件禁用应使用disabled或条件渲染。tabIndex仅允许出现在明确选择该模式的组件内部例如 roving tabindexEuiToolTip的直接子元素是键盘锚点若子元素本身可交互EuiButton、带tabIndex/href/onClick的元素则保持原样若不可交互EuiText、EuiImage、无onClick的EuiBadge、裸span、EuiIcon、EuiHealth、EuiAvatar等必须加tabIndex{0}否则键盘用户无法唤出 tooltip。EuiButton disabled{isDisabled} onClick{onSave}Save/EuiButton EuiToolTip content{i18n.translate(myView.infoTooltip, { defaultMessage: Info })} EuiText tabIndex{0}Read only/EuiText /EuiToolTip典型错误EuiButton tabIndex{-1}把按钮踢出 tab 顺序EuiToolTip contentDetailsEuiIcon typeinfo //EuiToolTip让键盘永远到不了 tooltip修正方式是给EuiIcon加tabIndex{0}。表单行isInvalid必须父子同步form_layout.md 解释EuiFormRow把label、hint、error接线到子控件只有当子控件的isInvalid与行的isInvalid一致时辅助技术播报与视觉错误样式才能保持一致。规范EuiFormRow带isInvalid{…}时直接子元素使用同一个表达式行上没有isInvalid子控件也不需要典型子控件EuiFieldText、EuiFieldNumber、EuiFilePicker、EuiComboBox、EuiTextArea、EuiSelect、EuiFormControlLayoutDelimited、SingleFieldSelect嵌套EuiFormRow时先同步最内层的父子对子元素若是{...fieldProps}先确认 spread 里是否已含isInvalidisInvalid是布尔值不做 i18n可见的label/error文本在新增或修改时走i18n.translate。EuiFormRow labelName isInvalid{!!errors.name} error{errors.name} EuiFieldText value{name} onChange{setName} isInvalid{!!errors.name} / /EuiFormRow图标与交互控件的命名层级icons_and_tooltips.md 规定每个EuiIcon要么装饰、要么语义二选一并如实标注装饰性→aria-hidden{true}且不得与tabIndex组合可聚焦节点必须可被感知语义性→ 给图标可访问名称aria-label或aria-labelledby原生title不是替代品——它只对内置图标类型生效对作为type传入的 SVG React 组件不支持单图标 tooltip 场景EuiIconTip是规范组件仅当需要多个 tooltip 子元素、子元素带EuiIconTip不支持的onClick/处理器或 tooltip 用到EuiIconTip不接受的 props 时才退回到EuiToolTipEuiIcon。迁移到EuiIconTip时搬运受支持的 propscontent、position、delay、title、id、aria-label、data-test-subj、icon 的type/color/size不要搬运tabIndex。interactive_components.md 则给出了交互控件EuiBetaBadge、EuiButtonIcon、EuiComboBox、EuiSelect、EuiSuperSelect、EuiPagination、EuiTreeView、EuiBreadcrumbs的命名层级自上而下停在第一层命中的地方已有aria-label/aria-labelledby且正确 → 保留有可见 labelEuiFormLabel、EuiTitle、label、邻近标题→ 用aria-labelledby 稳定 id 接线不要把文本复制进aria-label无可见 label →aria-label{i18n.translate(...)}。每个控件只使用一种机制。特别注意EuiFormRow已经为其直接子元素提供了名称——不要在 form row 内的控件上再加冗余aria-*。const fieldLabelId useGeneratedHtmlId(); EuiFormLabel id{fieldLabelId} Field (using {bucketAggType} buckets) /EuiFormLabel EuiComboBox aria-labelledby{fieldLabelId} {...rest} / EuiPagination aria-label{i18n.translate(results.pagination, { defaultMessage: Results pagination, })} pageCount{pageCount} activePage{activePage} onPageClick{onPageClick} /浮层Overlays让读屏名称与可见标题一致overlays.md 的选型与接线规则EuiModal——阻塞式确认或表单必须处理完才能继续EuiFlyout/EuiFlyoutResizable——非阻塞的细节/设置面板常与列表/页面选择搭配EuiConfirmModal——是/否或破坏性操作走titleprop APIEuiPopover——上下文菜单、过滤器或短锚定内容可能有也可能没有可见标题。规范写法是优先aria-labelledby指向可见标题保证读屏读出的名字与视觉所见一致在浮层内渲染真实标题EuiModalTitle、EuiFlyoutTitle、EuiPopoverTitle、EuiTitle或标题元素用useGeneratedHtmlId()类组件用htmlIdGenerator()给标题元素赋稳定id在浮层容器上设置aria-labelledby指向该 id一个 ID 变量同时用于标题和aria-labelledby——绝不产生悬空引用EuiConfirmModal的标题走 prop需通过titleProps{{ id }}把渲染出的 DOM 与aria-labelledby对齐确实无合适可见标题popover 的少见情况→ 退回aria-labeli18n.translate。建议的变量命名modalTitleId、flyoutTitleId、confirmModalTitleId、popoverTitleId。const flyoutTitleId useGeneratedHtmlId(); EuiFlyout aria-labelledby{flyoutTitleId} EuiFlyoutTitle id{flyoutTitleId}My title/EuiFlyoutTitle /EuiFlyoutconst confirmModalTitleId useGeneratedHtmlId(); return ( EuiConfirmModal aria-labelledby{confirmModalTitleId} title{i18nTexts.modalTitle} titleProps{{ id: confirmModalTitleId }} p{i18nTexts.modalDescription}/p /EuiConfirmModal );EuiPopover aria-labelledby{popoverTitleId} EuiPopoverTitle h2 id{popoverTitleId}Title/h2 /EuiPopoverTitle /EuiPopover常见错误用aria-labelSettings把可见标题复制成隐藏字符串EuiConfirmModal上aria-labelledby指向了一个从未通过titleProps.id接线的 id。Kibana 仓库的 file_flyout.tsx 是useGeneratedHtmlId flyout 接线的实际案例。Radio 分组name是可访问树的分组依据radio_groups.md单选按钮通过共享的name在可访问树中分组没有name浏览器和辅助技术无法把选项当作互斥集合。要点每个EuiRadio与EuiRadioGroup都必须有name同组选项共享同一个name同视图内不同组用不同的namename是程序性 token——不要套i18n可见的label文本在新增/修改时则要走i18n.translate命名从字段、分区或状态取camelCasepaymentMethod、alertSeverity避免radio1、group1、options上下文确实未知时optionGroup是可接受的最后手段但仍优于省略对{...groupProps}先在 spread 源头确认name是否已存在再添加。EuiRadio namepaymentMethod label{i18n.translate(payment.creditCard, { defaultMessage: Credit Card })} checked{selected credit} onChange{setSelected} / EuiRadioGroup namealertSeverity options{severityOptions} idSelected{selectedId} onChange{onSeverityChange} /Tooltip 三兄弟内容禁交互、图标按钮包裹、避免读屏重复tooltip 内容里禁止交互元素tooltip_content.md 解释了底层原因tooltip 的content与title渲染在roletooltip的 portal 中只在 hover/focus 期间存在blur 即消失——放在里面的任何可聚焦元素对键盘与辅助技术用户都不可达。允许纯字符串首选、非交互 JSX文本节点、span、p、EuiText、EuiIcon、以及不带onClick/href的展示型EuiBadge/EuiBetaBadge/EuiCard。禁止原生a/button/input等以及一长串交互 EUI 组件EuiLink、EuiButton、各类EuiField*、EuiComboBox、EuiPagination、EuiTab、EuiBasicTable等。规则会递归搜索——片段、条件渲染cond …、三元或包装元素里嵌套的交互元素同样会被报告。内容需要交互时的正解是换用EuiPopover并以显式点击而非 hover触发const [isOpen, setIsOpen] useState(false); const togglePopover () setIsOpen((open) !open); EuiPopover button{EuiButton onClick{togglePopover}More info/EuiButton} isOpen{isOpen} closePopover{() setIsOpen(false)} EuiLink href/docsLearn more/EuiLink /EuiPopover人工审查提示变量内容content{var}规则会静默跳过需自行追踪变量确认其中不含可聚焦 JSXEuiBadge/EuiBetaBadge/EuiCard一旦加上onClick/href即变为可聚焦同样受此限制。图标按钮必须“包裹 命名 去重”tooltip_icon.md 规定每个EuiButtonIcon需要两样东西给视觉用户的可见 tooltip用EuiToolTip包裹禁用原生title——浏览器 tooltip 无样式、无延迟控制、且在不同浏览器/AT 组合下读屏播报不可靠和给辅助技术的可访问名称保留aria-label。当 tooltipcontent与aria-label相同同字符串、同变量、同一次 i18n 调用时额外设置disableScreenReaderOutput让读屏只播报一次两者有意不同tooltip 是对名称的补充说明时则不加。const editLabel i18n.translate(myFeature.editItem, { defaultMessage: Edit item, }); EuiToolTip content{editLabel} disableScreenReaderOutput EuiButtonIcon iconTypepencil aria-label{editLabel} onClick{onEdit} / /EuiToolTip另一个容易犯的细节tooltip 与按钮各自用不同的 i18n id哪怕defaultMessage相同会导致文案漂移应当复用同一个 id。例外情形EuiButtonIcon作为设置了有意义beforeMessage的EuiCopyrender-prop 子元素时tooltip 已由EuiCopy提供不要再包——但仍需aria-labeltitle依然被禁止。仓库中 sidebar_title.tsx 同时使用了useGeneratedHtmlId与disableScreenReaderOutput是这套组合拳的现实样本。ESLint 规则 id → 组件指南映射references/eslint.md 是“从规则 id 出发”的二级入口每张表行的“Manual review”列列出规则无法自动解决、需要人工判断的形态。完整映射如下规则 id组件指南人工审查要点elastic/eui/accessible-interactive-elementfocus_and_keyboard.mdtabIndex只来自{...props}或 HOC不要重新设计 roving tabindexelastic/eui/badge-accessibility-rulesinteractive_components.mdEuiFormRow直接子元素行已提供名称{...props}含未知aria-*elastic/eui/callout-announce-on-mountcallouts.md{...props}展开且无显式announceOnMount始终挂载的 callout规则本不该触发elastic/eui/consistent-is-invalid-propsform_layout.md嵌套EuiFormRow先处理最内层对子元素为{...fieldProps}时确认 spread 未含isInvalidelastic/eui/icon-accessibility-rulesicons_and_tooltips.md{...iconProps}可能已包含 a11y propselastic/eui/no-nested-copy-tooltipcopy_tooltip.md无 autofix——EuiToolTip的content与beforeMessage无法自动合并需人工选定存活的文案经 helper/变量/map产生的 render-prop 根元素不被分析elastic/eui/no-unnamed-interactive-elementinteractive_components.mdEuiFormRow直接子元素行已提供名称{...props}含未知aria-*elastic/eui/no-unnamed-radio-groupradio_groups.md{...groupProps}展开——添加前先核实 spread 里的nameelastic/eui/prefer-eui-icon-tipicons_and_tooltips.md不是单一EuiIcon子元素icon 带onClick/不支持的 props——跳过或升级elastic/eui/require-aria-label-for-modalsoverlays.md{...props}隐藏接线无可见标题且加标题会改变 UX——升级人工处理elastic/eui/require-table-captiondata_tables.mdtableCaption仅经{...tableProps}提供——在源头修不要产生重复冲突的 captionelastic/eui/sr-output-disabled-tooltiptooltip_icon.mdEuiToolTipprops 来自 spread子元素不是EuiButtonIconelastic/eui/tooltip-button-icon-wraptooltip_icon.md · copy_tooltip.md无显式title的{...props}被静默跳过——核实 spread 未省略 tooltip按钮无aria-label时 autofix 无法运行aria-label与EuiToolTipcontent都要给位于带有意义beforeMessage的EuiCopy内时不报告tooltip 由EuiCopy提供——不要在那里加包裹elastic/eui/tooltip-focusable-anchorfocus_and_keyboard.md{...anchorProps}或未知自定义锚点elastic/eui/tooltip-no-interactive-contenttooltip_content.md变量内容content{var}/title{var}被静默跳过——需追踪并核实带onClick/href的EuiBadge/EuiBetaBadge/EuiCard变为可聚焦需迁移到EuiPopover仓库中的规范落地验证从源码结构看上述规范并非停留在文档层面Kibana 的现有代码已经成规模地遵循这套模式tableCaption在 sessions_mgmt 表格 等多处表格组件上显式提供与require-table-caption规则的要求一致announceOnMountinteractive_setup 的错误 callout 等条件渲染 callout 均带该 prop对应callout-announce-on-mount规则的规范模式id 接线file_flyout.tsx 使用useGeneratedHtmlId为 flyout 标题接线类组件一侧vis_default_editor 的 controls/filters.tsx 仍在使用htmlIdGenerator与共享原则中“函数组件/类组件各用其器”的表述相互印证disableScreenReaderOutputsidebar_title.tsx、sidebar.tsx 等处的图标按钮 tooltip 均按“content 与 aria-label 同源 去重”的模式书写。这些路径可以作为学习规范模式的真实样本遇到同类组件时直接对照相应源码即可确认规范写法。小结Kibana 的无障碍规范体系由三层构成共享原则WCAG 2.2 AA、APG、EUI 优先、语义优先、决策顺序、i18n 与 id 生成、最小变更与升级条件→组件指南11 份覆盖 callout、复制 tooltip、表格、焦点键盘、表单、图标、交互控件、浮层、radio、tooltip 内容与图标按钮→ESLint 映射表14 条elastic/eui规则到组件指南的跳转与人工审查清单。其核心工程思想可以概括为用稳定的 id 接线可见文本而非复制字符串用组件内建 props表达语义而非后期补 ARIA用单一 i18n 来源保证视觉提示与读屏播报不漂移当{...props}展开、缺少可见标题或需求冲突导致无法静态判断时按共享原则的“升级时机”交还人类审查而不是猜测。遵循这套流程无障碍不再是 lint 报错后的补丁而是 EUI 组件从第一行 JSX 就内建的属性。【免费下载链接】kibanaYour window into all of your data项目地址: https://gitcode.com/GitHub_Trending/ki/kibana创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考