こんにちは、SmartHR プロダクトエンジニアの ceris と gaha です。
複雑な UI コンポーネントの実装において、アクセシビリティの確保は難しい課題の1つです。 この記事では、smarthr-ui で提供している階層構造のフォーム UI コンポーネントについて、アクセシビリティを考慮しながら、どのように複雑なUIを実現したのか、その実装アプローチとアクセシビリティへの取り組みをご紹介します。
目次
- 目次
- smarthr-ui で提供している階層構造のフォーム UI
- アクセシビリティのこだわりポイント
- 階層構造のフォームUIが smarthr-ui でコンポーネントとして提供されるまで
- まとめ
- We are hiring!
smarthr-ui で提供している階層構造のフォーム UI
smarthr-ui では階層構造のフォーム UI をBrowserという名称で提供しています。 実際の挙動については以下のようになっています。
Browser | コンポーネント | SmartHR Design System
階層表現を実現するための実装の説明
フォームの挙動としては「階層構造を持ったラジオボタン」のような振る舞いをしています。 第一階層の項目を選択すると、その子階層にあたる第二階層のフォームが描画され、第二階層の項目を選択すると、その子階層にあたる第三階層のフォームが描画され...といった形でフォームの選択状態に応じて再帰的にフォームをレンダリングするような実装になっています。
このようなフォームの構造はItemNodeLike 型で表現しており、childrenプロパティとして自身の型を再帰的に参照するような定義で表現しています。
利用例
選択項目の総量が多く、一定の分類が可能なフォームを用意したい場合に活用できます。 現状、SmartHR ではHRアナリティクスという機能で利用しています。
一方で、通常のフォームと比較して表示領域が大きくなりやすいコンポーネントではあるため、シンプルなフォーム表現がしたい場合はやや不向きです。基本的にはダイアログ上など、ある程度コンテンツ領域を確保しやすい場所で利用することが多くなるかなと思います。
アクセシビリティのこだわりポイント
Browser コンポーネントでは、次のようなポイントでアクセシビリティを考慮した実装を行っています。
デスクトップアプリのようなUIのマークアップ ── application ロールの活用
Finderのようなデスクトップアプリケーションの操作感に近いUIであることをスクリーンリーダーに伝えるために、role="application"を指定しています。
通常、スクリーンリーダーなどの支援技術は、ウェブページを「文書」として解釈し、見出しやリンクなどの標準的なHTML要素をもとにナビゲーションをする機能をユーザーに対して提供します。 対して、application ロールを要素に指定した場合、その要素の配下の領域は文書ではなくデスクトップアプリケーションのように扱われ、ユーザーはそのUIに対して直接的なキーボード操作が可能になります。
ただし、application ロールの使用は慎重に検討する必要があります。 なぜなら支援技術に頼らず、使いやすいキーボード操作の挙動を自前で満たす必要があるからです。 Browser コンポーネントの場合、以下の点において使いやすい操作感を実現しています。
- ユーザーの期待と一致した操作モデル
- Finderライクな階層構造の探索という、ユーザーにとって馴染みのある操作モデル
- キーボード操作のサポート
- 矢印キーによる移動など、デスクトップアプリケーションと同様の操作性(キーボードインタラクションの項にて後述)
階層構造のフォームのマークアップ ── input type="radio" の指定
選択状態を表現するためにinput type="radio"及びchecked属性を利用しています。
Browser コンポーネントが最終的に1つの項目を選択するためのコンポーネントであり、必然的に各階層から選択できる項目は 1 つのみであるためです。
しかしながら見た目はラジオボタンとは異なるので、Tailwind CSS のsr-onlyクラスを用いてスクリーンリーダーのみにラジオボタンの選択状態が伝わるような工夫をしています。
階層構造のリスト表現のマークアップ ── aria-owns による親子関係の明示
Browser コンポーネントは親子関係を持つ階層構造を表現するフォームUIのコンポーネントとして実装されていますが、各階層の列が横向きに並列に並べられている視覚的な構造のため、情報としての親子関係をDOMで正しく表現できない問題がありました。
そこで親要素にaria-ownsを指定することで、DOMの構造に関係なく、親子関係をスクリーンリーダーに伝えるようにしています。
aria-ownsは、視覚的なレイアウトとは独立して要素間の意味的な所有関係(親子関係)を定義できるARIA属性です。つまり、DOMツリー上は別の場所にある要素でも、スクリーンリーダーに対して親子関係があることを明示できます。
たとえば以下のようなマークアップにより、列として並んでいるリストでも、スクリーンリーダーには階層構造として伝わります。理想的にはDOMの構造自体で親子関係を表現することが望ましいですが、レイアウト上の制約がある場合にはaria-ownsが有効な代替手段となります。
<div class="container"> <!-- 第一階層 --> <ul class="column"> <li aria-owns="child-list">親カテゴリ1</li> <li>親カテゴリ2</li> </ul> <!-- 第二階層 --> <ul id="child-list" class="column"> <li>子カテゴリ1-1</li> <li>子カテゴリ1-2</li> </ul> </div>
キーボードインタラクション ── ツリービューパターン
キーボードインタラクションについてはW3Cが提供する標準的なアクセシビリティガイドラインである APG(ARIA Authoring Practices Guide)を参考に実装しており、階層構造を持つUIのパターンとしてTree View Patternに基づいて、以下のような操作を可能にしました。
- 階層内の移動
- 上下矢印キーで、同じ階層内の項目間を移動
- 階層間の移動
- 右矢印キーで、子階層へ移動(選択中の項目に子階層がある場合)
- 左矢印キーで、親階層へ移動
- Enter/Spaceで、子階層へ移動(選択中の項目に子階層がある場合)
これらの操作方法は、macOSの Finder など、普段使い慣れたアプリケーションと同様の操作感であり、結果的にユーザーがUIを経験を元に操作しやすくなっています。
階層構造のフォームUIが smarthr-ui でコンポーネントとして提供されるまで
ここまで、Browser コンポーネントのアクセシビリティにおいて意識したことを説明しました。 ここからは、Browser コンポーネントがどういった経緯で smarthr-ui で提供されるようになったかの経緯を説明します。
HRアナリティクス機能での実装
先述したように Browser コンポーネントはHRアナリティクスという機能で利用されています。 そのため当初は smarthr-ui ではなく、HRアナリティクス固有のコンポーネントとして実装を行いました。
SmartHR にはアクセシビリティのスペシャリストが複数名在籍しており、その方々に実装方針の相談や、作成したコンポーネントのアクセシビリティの検証などを依頼できるチャンネルが用意されています。 まずはHRアナリティクスの開発チームで要件を検討し、UIの方針を決めてから、アクセシビリティの観点での懸念事項などをまとめて相談チャンネルで確認する、という流れで進めました。
HRアナリティクスの開発チームから相談していた内容は以下のようなものでした。
- 直列(階層なし)で表現するには項目数が多すぎるフォームがあり、特定の分類で分けられるような階層構造を持ったUIを考えたい
- Finder のようなディレクトリ構造で表現したい
- キーボード操作や読み上げなどのアクセシビリティの配慮を欠かさないようにしたうえで、HTMLのセマンティクスも維持したい
その返答としてアクセシビリティのスペシャリストのメンバーから「アクセシビリティのこだわりポイント」で記載したようなaria-ownsによる親子関係の表現や「 File Directory Treeview Example Using Computed Properties | APG | WAI | W3C」のようなモデルとなる実装パターンのヒントを提供していただきました。
これらを参考にしつつコンポーネントの設計を詰めていき、試験的な実装をしながら都度挙動に対してフィードバックをもらい、「ウェブアクセシビリティ簡易チェックリスト SmartHR Design System」の検証をした上でリリースを行なっています。
SmartHR ではこのように特定の専門性を持ったスペシャリストと相談や壁打ちをしながら実装を進めることができるので、質の高いUIを提供できるだけでなく、自身やチームの知識のインプットといった成長の機会にも富んでいます。 個人的にはこの体制はとてもよい福利厚生だと感じています。
smarthr-ui への移植
SmartHR では従業員情報やタレントマネジメントのための様々データを扱っています。 ユーザー独自に項目を増減することもできるため、利用ケースによっては数百項目の内から目的の項目を探索しなければならない場合もあります。 これらを扱うそれぞれのプロダクトでは、独自の意匠を凝らした新規のコンポーネントを定義したり、似たようなユースケースの前例があるプロダクトからコンポーネントを輸入するような形で秘伝のタレ的に継承されたりしていました。これにより、プロダクト間で表現や操作感に若干の差異が発生したり、SmartHR 全体での一貫性は徐々に失われていくことになります。
こうした背景から、HRアナリティクスの開発メンバーと smarthr-ui のコアメンバーと協議を進めつつ、smarthr-ui への組み込みに至りました。
このように、特定のプロダクトから各プロダクトで利用可能なコンポーネントとして昇華できるところも SmartHR の強みであると感じました。何より、開発チームで色々と思考を巡らせて作成したコンポーネントが評価され、全社的に利用できるよう整備されていくことは嬉しいですし、モチベーションにも繋がります。
まとめ
この記事では、SmartHR の Browser コンポーネントを例に、複雑な階層構造を持つフォームUIをアクセシビリティを考慮しながら実装した事例を紹介しました。 また、アクセシビリティのスペシャリストとの協働や、プロダクト固有の実装から全社的に利用可能なコンポーネントへの昇華など、SmartHR におけるUI開発の特徴的なアプローチについても触れました。 このように、SmartHR ではアクセシビリティを考慮したUI実装は、専門家との連携や知見の共有によって実現されています。
We are hiring!
SmartHR では、アクセシビリティを大切にしながらプロダクト開発に取り組む仲間を募集しています。ユーザーにとって使いやすいプロダクトづくりに興味がある方、ぜひ一緒に働きませんか?