Design System 101 - Roving Focus
- 文章發表於
前言
在設計系統中,有許多組件都是以群集 (Group) 的方式去呈現,如 TabList, Radio Group 又或是 Checkbox 等等,而當鍵盤使用者在操作頁面時,往往都需要透過 Tab 一個個去切換聚焦又或是沒辦法對聚焦到群集裡面的項目。
Roving Focus (或又稱 Roving TabIndex) 就是在群集組件中,提供能夠讓鍵盤使用者能夠更輕易與更有效率的方式操作頁面。能夠透過 Arrow 鍵來對聚焦進行切換,當使用者想要切換到下一個區塊只需要再按一次 Tab 鍵即可。
前後對比
加了 Roving Focus 之前
使用者聚焦在群集的第一個項目後,如果想要到將聚焦移到輸入框必須連續按好幾下 Tab 鍵且無法透過 Arrow 鍵來切換項目間的聚焦。
加了 Roving Focus 之後
使用者可以透過 Arrow 鍵來切換聚焦,並且當使用者想要切換到下一個區塊只需要再按一次 Tab 鍵即可。
其概念就是監聽 group 中的 keydown 事件,當使用者按下 Arrow 鍵時,就會將 selected 移動到下一個 index, 並將 tabIndex 設為 0,以及將原本的項目 tabIndex 設為 -1,並將新的項目進行聚焦。
React 實作
在介紹如何用 React 實作 Roving Focus 時,會使用到先前在 設計模式 x 複合組件 中 Collection API 的概念,如果還沒看過的讀者,可以先閱讀一下。
使用方式
// <GroupItem />() => (<RovingFocusGroup reachable loop><GroupItem /></RovingFocusGroup>)// <Item />() => {const rovingFocusProps = useRovingFocus({ disabled, active: isSelected })return <Item {...rovingFocusProps} />}
`RovingFocus` 的實作概念
- createCollection:- 將 group內可被聚焦的item進行收集,並透過useContext來取得 collection。
 
- 將 
- useRovingFocus:- 透過 useEffect來監聽tabStopId的變化,當tabStopId變化時,就會將tabIndex設為 0,並將原本的項目tabIndex設為 -1,以及將新的項目進行聚焦。
- 將聚焦邏輯進行封裝,讓 group底下的item能夠根據不同的鍵盤事件進行聚焦狀態的改變。
 
- 透過 
- <RovingFocusGroup />:- 主要是將 groupId,collection與tabStopId等的狀態透過createContext傳遞給子組件。
 
- 主要是將 
import React from 'react' import { RadioGroup, Radio } from './radioGroup.jsx' export default () => { return ( <> <h3 id="drink-options">Drink Options</h3> <RadioGroup loop> <Radio value="Water">Water</Radio> <Radio value="Tea">Tea</Radio> <Radio disabled value="Coffee"> Coffee </Radio> <Radio value="Ginger Ale">Ginger Ale</Radio> </RadioGroup> <div> <input type="text" placeholder="Tab Me" /> </div> </> ) }
