フォーム・入力
ボタン
解説ありButton
すべての基本。button 要素を使えば得られるアクセシビリティと、自作の落とし穴。
ボタンとは?
ボタンは、押すと「その場で何かが起きる」操作のための部品です。 送信・いいね・モーダルを開く・再生/停止など、ページ内のアクションを実行するときに使います。
Web には最初から <button> という専用要素があり、これを使うだけで、押せること・キーボード操作・支援技術への通知が自動的に揃います。
なぜアクセシビリティが大事なの?
「クリックできる <div>」は、マウス利用者には動いて見えますが、次の人たちには壊れています。
- キーボードだけで操作する人。
<div>は Tab でフォーカスできず、 たどり着くことすらできません。 - スクリーンリーダーを使う人。「ボタン」と読み上げられないため、押せると気づけません。
- 誰にとっても。
<div>にはdisabledの概念がなく、 無効状態を正しく伝えられません。Space でも反応しません。
<button> なら、これらすべてが最初から解決されています。
ライブデモ(推奨実装)
下の2つのボタンは APG に沿った実装です。マウスを使わず、Tab で移動し Enter と Space の両方で押してみてください。
試してみよう:Tab でフォーカス → Enter でも Space でも数が増える。disabled のボタンはフォーカスも反応もしない。
ポイント
スクリーンリーダーでフォーカスすると「いいね, ボタン」、無効なほうは 「送信済み, 淡色表示, ボタン」のように役割と状態が読み上げられます。 これらは <button> と disabled 属性だけで自動的に得られます。
キーボード操作
| キー | 動作 | 必須/任意 |
|---|---|---|
| Tab | 次 / 前のボタンへフォーカス移動(無効なボタンは飛ばされる) | 必須 |
| Enter | フォーカス中のボタンを押す | 必須 |
| Space | フォーカス中のボタンを押す | 必須 |
補足
<button> なら、この表のすべてがコードを書かずに動きます。リンク(<a>)は Enter のみ、ボタンは Enter と Space の両方で 活性化するのが正しい挙動です。
必要な WAI-ARIA / ロール
| 付ける場所 | 属性 / ロール | 意味 |
|---|---|---|
| ボタン(推奨) | <button type="button"> | ロール・フォーカス・キー操作がすべて自動。ARIA は基本不要。 |
| フォーム送信 | type="submit" / type="button" | 意図しない送信を避けるため、送信でないボタンには type="button" を付ける。 |
| 無効化 | disabled | 操作不可にし、フォーカスからも外す。支援技術にも伝わる。 |
| div で代用する場合のみ | role="button" + tabindex="0" | 「ボタン」と認識させ、フォーカス可能にする。さらにキー処理の自作が必須。 |
実装:推奨パターン(Good)
良い例 / 推奨
迷ったら <button>。click を1つ書くだけで全入力手段に対応します。
マークアップ:
<!-- これだけで「ボタン」として完璧に動く -->
<button type="button" id="like-btn">
いいね(<span id="like-count">0</span>)
</button>スクリプト(click だけでマウス・Enter・Space をカバー):
const btn = document.getElementById('like-btn');
const count = document.getElementById('like-count');
if (btn && count) {
// click だけ書けば、マウス・Enter・Space すべてで発火する
btn.addEventListener('click', () => {
count.textContent = String(Number(count.textContent) + 1);
});
}補足
どうしても <div> で作らざるを得ないときは、最低でもrole="button"・tabindex="0"・Enter/Space のキー処理が必要です。<button> 1つで済むものが、これだけ増えます。
<!-- どうしても div で作る場合(非推奨)に最低限必要なもの -->
<div role="button"
tabindex="0"
id="like-div">
いいね
</div>const el = document.getElementById('like-div');
if (el) {
el.addEventListener('click', activate);
// button なら不要な「キー処理」を自前で書く必要がある
el.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault(); // Space のスクロールを止める
activate();
}
});
}
function activate() { /* ... */ }アンチパターン(Bad)
下は <div> に onclick を付けただけの「ボタン風」です。マウスでは押せますが、キーボードでは触れず、Space でも反応しません。上のデモと比べてみてください。
試してみよう:Tab で到達できず、Space でも反応しません。スクリーンリーダーでは「ボタン」と読み上げられず、無効状態も表現できません。
<!-- ❌ アンチパターン:div を onclick で「ボタン風」にしただけ -->
<div class="btn" onclick="like()">いいね</div>悪い例 / 避ける
この実装の問題点:
- キーボードでフォーカスできない —
divは Tab の対象外。 - Space / Enter で動かない — キー処理を自作していない。
- 役割が伝わらない — スクリーンリーダーに「ボタン」と認識されない。
- 無効化できない —
disabledの概念がなく、押せない状態を伝えられない。
ポイント
「リンクっぽい見た目だけどページ移動しない」ものや、「ボタンっぽいけど別ページへ飛ぶ」ものは混乱のもとです。その場で何かを実行するなら <button>、別の場所へ移動するなら <a href> と 役割で選びましょう。
実装チェックリスト
- 操作(実行)の部品は
<button>を使っている - 送信でないボタンには
type="button"を付けている - マウス・Enter・Space のすべてで動く
- 無効にしたいときは
disabledを使っている - フォーカスが見える(フォーカスリングを消していない)
- (div 代用時のみ)
role="button"・tabindex="0"・キー処理をすべて足している