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> </> ) }