Slide 1

Slide 1 text

たかがボタン、されどボタン button 要素から深ぼるボタンUI の定義について BuriKaigi 2026 Day2 | 2026-01-10 ドキュメントページ やまのく(yamanoku )

Slide 2

Slide 2 text

今日 どんなボタンを 押してきましたか?

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

やまのく(yamanoku ) 一児の父。会社員 千葉県在住 BuriKaigi 初参加 家族で初富山 この発表を𝕏へポストしてみよう!

Slide 5

Slide 5 text

ボタンとは何か?

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

様々なボタンたち 送信 キーワードを入力 🔍 検索 🔊 ミュート 小 中 大 ← 戻る 次へ →

Slide 8

Slide 8 text

アフォーダンス

Slide 9

Slide 9 text

シグニファイア ボタンが無効であるかどうか 送信する 送信する アイコンで何ができるかを表す

Slide 10

Slide 10 text

GUI Xerox Alto and Xerox 8010 Star

Slide 11

Slide 11 text

スキューモフィズム iPhone 登場~iOS6

Slide 12

Slide 12 text

フラットデザイン

Slide 13

Slide 13 text

これはボタンなのか?

Slide 14

Slide 14 text

ニューモフィズム・グラスモーフィズム ニューモフィズムボタン グラスモーフィズムボタン

Slide 15

Slide 15 text

マテリアルデザイン https://github.com/material-components/material-web/blob/main/docs/components/button.md

Slide 16

Slide 16 text

フラットデザインの影響 ハイパーリンク表現によるボタン

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

1: type 属性を忘れた

Slide 22

Slide 22 text

郵便番号 住所検索 都道府県 市区町村 番地 送信する

Slide 23

Slide 23 text

HTML Living Standard

Slide 24

Slide 24 text

type 値 挙動 submit フォームを送信する reset フォームをリセットする button 何もしない(スクリプト用)

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

HTML 2.0 HTML 4.0

Slide 27

Slide 27 text

住所検索 送信する 住所検索 送信する

Slide 28

Slide 28 text

Lint ルールで防ぐ html-eslint: @html-eslint/require-button-type eslint-plugin-react: react/button-has-type eslint-plugin-vue: vue/html-button-has-type angular-eslint: @angular-eslint/template/button-has-type eslint-plugin-svelte: svelte/button-has-type Biome: lint/a11y/useButtonType Deno lint: jsx-button-has-type

Slide 29

Slide 29 text

Markuplint で独自設定 { "rules": { "required-attr": true, }, "nodeRules": [ { "selector": "button", "rules": { "required-attr": { "value": [ { "name": "type", "value": ["button", "reset", "submit"] } ], } }

Slide 30

Slide 30 text

type にまつわる余談 ①新しいtype 属性が提案されていた・いる type="share" (未採択) Web Share API のボタン type="selectlist" (未採択) 要素内でリストボックスを開くためのボタンのため type="press" (提案中) 押下されている状態を表現

Slide 31

Slide 31 text

type にまつわる余談 ②type 属性のデフォルト値を変えたい! Investigate making the invalid state of not submit · Issue #10462 · whatwg/html type が無効値のときにsubmit 扱いになる現在仕様を見直す提案が議論されている 互換性リスクや既存サイトへの影響が大きく、仕様変更には慎重な検討が必要とさ れている 代替案として、仕様の明確化やlint 的な警告など、破壊的変更を避ける方向性も示さ れている

Slide 32

Slide 32 text

Slide 34

Slide 34 text

振る舞いに注目

Slide 35

Slide 35 text

ARIA Authoring Practices Guide Button "A button is a widget that enables users to trigger an action or event, such as submitting a form, opening a dialog, canceling an action, or performing a delete operation." (ボタンは、フォーム送信、ダイアログを開く、アクションのキャンセル、削除操作など、アク ションやイベントをトリガーするウィジェットです) Link "A link widget provides an interactive reference to a resource. The target resource can be either external or local." (リンクは、リソースへの対話的な参照を提供します。対象リソースは外部でもローカルでも構 いません)

Slide 36

Slide 36 text

ボタン リンク 目的 アクション実行 ナビゲーション 期待される結果 何かを実行する ページ遷移・特定位置に移動する 例 モーダルを開く、削除する 別ページへ移動 リンクはどこかへ移動する、ボタンは何かをする ものと定義できる

Slide 37

Slide 37 text

キーボード操作 Button Space : Activates the button. Enter : Activates the button. Link Enter : Executes the link and moves focus to the link target. Shift + F10 (Optional): Opens a context menu for the link.

Slide 38

Slide 38 text

リンクそのものの処理を除外する処理 const link = document.getElementById('link'); link.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); link.click(); } }); link.addEventListener('keyup', (e) => { if (e.key === ' ') { e.preventDefault(); } }); link.addEventListener('contextmenu', (e) => { e.preventDefault();

Slide 39

Slide 39 text

Slide 40

Slide 40 text

リンク遷移させるなら を使う

Slide 41

Slide 41 text

3:
で実装されたボタンUI

Slide 42

Slide 42 text

ボタン

Slide 43

Slide 43 text

✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ 👉 👈 ⚡ 今すぐ押して! ⚡

Slide 45

Slide 45 text

HTML の役割は支援技術に伝わる

Slide 46

Slide 46 text

スクリーンリーダーでの違い button 「ボタン、ダイアログを開く」 div 「ダイアログを開く」 ダイアログを開く
ダイアログを開く

Slide 47

Slide 47 text

Web Content Accessibility Guidelines (WCAG)

Slide 48

Slide 48 text

4.1.2 名前 (name) ・役割 (role) ・値 (value) 達成基準 すべてのユーザインタフェース コンポーネント ( フォームを構成する要素、リンク、スクリプト が生成するコンポーネントなど) では、名前 (name) 及び役割 (role) は、プログラムによる解釈が 可能である。 役割を上書きすることで「ボタン」と読み上げられる しかし 本来がもつキーボード操作は付与されていない
ダイアログを開く

Slide 49

Slide 49 text

2.1.1 キーボード ( レベル A) 達成基準 コンテンツのすべての機能は、個々のキーストロークに特定のタイミングを要することなく、キ ーボードインタフェースを通じて操作可能である。 他にも Enter や Space でアクションさせる挙動も必要 Enter はkeydown で発火し、押しっぱなしだと連続で発火する Space はkeyup で発火するが、押しっぱなしのまま Tab でフォーカス移動すると発 火しない
ダイアログを開く

Slide 50

Slide 50 text

ガイドラインから学ぶ鉄則 Using ARIA If you can use a native HTML element or attribute with the semantics and behavior you require already built in, instead of re-purposing an element and adding an ARIA role, state or property to make it accessible, then do so. (必要なセマンティクスと振る舞いを持つネイティブHTML 要素が使えるなら、ARIA で無理やり 作るのではなく、それを使ってください) ARIA Authoring Practices Guide No ARIA is better than Bad ARIA (悪いARIA より、ARIA を使わない方がマシである)

Slide 51

Slide 51 text

ざんねんなボタンUI 実装への対処方法 ① type 属性を忘れた の挙動を正しく理解し、適切なtype 属性を付与する ② で実装されたボタンUI HTML 要素がもつ役割を正しく認識し、適切な場面で適切な要素を扱うようにする ③
で実装されたボタンUI

Slide 52

Slide 52 text

おわりに

Slide 53

Slide 53 text

No content

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

たかがボタン、されどボタン

Slide 56

Slide 56 text

Thank You For Listening !!