無障礙存取
@lh-ui/react 與家族其他庫共享同一套無障礙契約:語義化標籤、ARIA 屬性、鍵盤互動全部在 @lh-ui/share/core 內定義,各端實作一致。本庫額外保證 React 生態的常見 a11y 陷阱不出現。
語義與 ARIA
LhSwitch渲染<div role="switch" aria-checked>,而非視覺偽裝的 checkboxLhSelect觸發器為role="combobox",展開面板為role="listbox",選項為role="option",並用aria-activedescendant同步鍵盤高亮LhDialog為role="dialog" aria-modal,標題同時提供aria-label兜底與aria-labelledby精確關聯LhTooltip用aria-describedby把提示關聯到觸發器LhTag可點選時升級為role="button",並回應 Enter / SpaceLhFormItem驗證失敗渲染role="alert"錯誤提示,並設定aria-invalid
鍵盤互動
| 元件 | 鍵位 |
|---|---|
LhButton / LhTag | Enter / Space 觸發點選 |
LhSwitch | Enter / Space 切換 |
LhSelect | ArrowUp / ArrowDown 高亮選項,Enter 選取,Escape 收起 |
LhDialog | Escape 關閉(僅棧頂彈層回應) |
LhTooltip | Escape 關閉 |
多彈層疊加時用 useLhOverlayStack 維護開啟順序棧,Escape 只關棧頂,避免一次按鍵帶走全部彈層。
焦點管理
LhDialog開啟時用useLhFocusTrap把焦點限制在對話框內(Tab / Shift+Tab 不外逃),關閉後焦點歸還觸發器LhFormItem點選 label 時聚焦內容區首個可聚焦元素(focusControl),原生 label 包裹行為在複合控制項上不可靠
裝飾性圖示
LhIcon 預設 decorative:輸出 aria-hidden="true",對螢幕閱讀器不可見。需要語義時傳 decorative={false} + ariaLabel:
<LhIcon name="search" decorative={false} ariaLabel="搜索" />
此時渲染 <svg role="img" aria-label="搜索">。
StrictMode 安全
所有元件在 React StrictMode 下安全:effect 的 cleanup 與重複掛載都做了冪等處理(彈層棧註冊 / 卸載、捲動鎖的持鎖者校驗、focus trap 的釋放)。
家族一致性
無障礙行為登記在 docs/设计语言基线.md,是雙血脈(web / 原生)的統一契約。各端按同一份 @lh-ui/share/core 邏輯實作,aria 屬性與鍵位語義一致。