Tabについて - React Ariaの実装読むぞ
こんにちは、フロントエンドエンジニアの mehm8128 です。
今日は Tab について書いていきます。
使用例
ドキュメントからそのまま取ってきています。
function Tabs(props) {
let state = useTabListState(props);
let ref = React.useRef(null);
let { tabListProps } = useTabList(props, state, ref);
return (
<div className={`tabs ${props.orientation || ""}`}>
<div {...tabListProps} ref={ref}>
{[...state.collection].map((item) => (
<Tab key={item.key} item={item} state={state} />
))}
</div>
<TabPanel key={state.selectedItem?.key} state={state} />
</div>
);
}
function Tab({ item, state }) {
let { key, rendered } = item;
let ref = React.useRef(null);
let { tabProps } = useTab({ key }, state, ref);
return (
<div {...tabProps} ref={ref}>
{rendered}
</div>
);
}
function TabPanel({ state, ...props }) {
let ref = React.useRef(null);
let { tabPanelProps } = useTabPanel(props, state, ref);
return (
<div {...tabPanelProps} ref={ref}>
{state.selectedItem?.props.children}
</div>
);
}
本題
APG はこちらです。
aria-
属性
role と1 つ 1 つのタブボタンはtab
role、それらを囲っているものがtablist
role、タブ選択時にコンテンツが表示される領域がtabpanel
role です。
全てのtab
role にはそれぞれに対応するtabpanel
の id をaria-controls
に指定し、さらにアクティブなtab
role にはaria-selected="true"
をつけます。
キーボード操作
Tab キーで現在アクティブなタブにフォーカスが当たり、矢印キーでタブの移動ができます。
また、タブにフォーカスが当たっているときに Tab キーを押した場合、タブパネルがその中に Tab キーによってフォーカス可能な要素を含んでいればその要素にフォーカスが当たります。Tab キーによってフォーカス可能な要素を含んでいなければタブパネル自体がtabindex="0"
になってタブパネル全体にフォーカスが当たります。
(注意: tabbale
、tabbing
は Tab キーでフォーカスできる、Tab キーを押す、などの意味で、tab
はタブコンポーネントを意味しています)
タブの配置方向
縦に配置する場合と、左右反対に配置するパターンがあります。
縦に配置する場合はaria-orientation="vertical"
をつけ、上下矢印キーでタブを移動できるようにします。
また、右から左に読む言語を利用している場合、最初のタブが一番右、最後のタブが一番左に配置されるようにする必要があり、さらにキーボード操作も左右逆にします。ドキュメントのデモ部分で devtools からdir="ltr"
をdir="rtl"
にすると体験できます。
Pointer Cancellation
過去に こんな issue がありました。
WCAG の Success Criterion 2.5.2 Pointer Cancellationに準拠せず、pointerdown のタイミングでしかタブの選択ができなかった時期があったようです。今回のケースは 4 つ挙げられているパターンのうちの「Abort or Undo」に当たると思います。
そこで、useTab: adds support for shouldSelectOnPressUp #4342でshouldSelectOnPressUp
props がサポートされ、間違えてタブをクリック(pointerdown)してしまったときでも pointerup する前にタブからカーソルを移動すればタブの選択をキャンセルすることができるようになりました。
aria-controlsについて
最初に述べたaria-controls
について、コントロールする側とされる側の要素を紐づけるために付与するべきなのは分かっているのですが、スクリーンリーダーでの読み上げに特に影響しているわけではなさそうで、サービスの利用者目線で具体的に何かメリットがあるのか気になっていました。そこで、1 つ記事を見つけたので共有します。
aria-controls
とaria-owns
の違いを説明する記事なのですが、So, how are they different?でaria-controls
について説明されています。特に「Does ARIA Controls have good support?」のセクションでスクリーンリーダーなどのサポート状況について述べられていて、Accessibility Supportを確認すると JAWS というスクリーンリーダーでのみaria-controls
に対してなんらかのサポートを行っていることが説明されています。とはいえアクセシビリティツリーにはaria-controls
の値が公開されているので、今後他のスクリーンリーダーでもサポートされる可能性はあり、そのときのためにつけておくのがよさそうということらしいです。
W3C や NVDA のリポジトリで、aria-controls
に対してどのようなサポートをするべきか議論されているような issue も見つけたので読んでみるといいかもしれません。
まとめ
明日の担当は @mehm8128 さんで、番外編 Focus Management API について(概要編)の記事です。お楽しみにー
Discussion