ボタンの役割と動作を一致させる
問題:ボタンではない要素にクリックイベントリスナーを付与している
通常の HTML 要素にcursor: pointerとonclickイベントだけを追加しても、本当のボタンにはなりません。このやり方だと、キーボード利用者はキーボードでフォーカス移動ができず、スクリーンリーダー利用者もボタンとして認識できない可能性があります。
リンクにも同じことが当てはまります
<a>タグを使わずにハイパーリンクを実装した場合も同じ問題が発生します。
リンク可能な要素には必ず<a>タグを使用してください。<button>と違って<a>はブロック要素を子に含められるため、用途を取り違えて代替として使わないでください。
誤った例
次のようなコードは、上で説明したすべてのアクセシビリティ問題を引き起こします。
jsx
<div class="button-style" style="cursor: pointer" onclick="handleAnything()">
お問い合わせ
</div>✅ 改善方法
1. <button>要素を使う
最もよい方法は、HTMLのセマンティック要素である<button>を使うことです。この要素は基本的なアクセシビリティ機能をすべて提供します。
- キーボードフォーカス
- Enter/Space キーでのクリック
- スクリーンリーダーで「ボタン」として認識
- 適切な ARIA 属性の自動付与
jsx
<button onClick={handleClick}>문의하기</button>2. <button>を使えない場合
内部にブロック要素があり<button>を使えない場合は、次のようにアクセシビリティ属性を明示する必要があります。
jsx
<div
role="button"
tabIndex={0}
onClick={handleClick}
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
handleClick();
}
}}
>
<div>内部のブロック要素</div>
</div>role="button":スクリーンリーダーにこの要素がボタンであることを知らせます。tabIndex={0}:キーボードでフォーカスできるようにします。onKeyDown:キーボードアクセシビリティのため、EnterまたはSpaceキー入力時にクリック相当の動作を発生させます。
3. react-ariaを使う
React-Ariaライブラリの useButtonフックを使うと、アクセシブルなボタンをより簡単に実装できます。このフックは role、tabIndex、onKeyDown などの必須アクセシビリティ設定をまとめて提供してくれるため、個別に扱う必要がありません。
jsx
import { useButton } from "react-aria";
const buttonRef = useRef < HTMLDivElement > null;
const { buttonProps } = useButton(
{
elementType: "div",
onPress: handleClick
},
buttonRef
);
<div ref={buttonRef} {...buttonProps}>
<div>内部のブロック要素</div>
</div>;