HTML

A friendly, step-by-step page that shows how to make buttons that do things — simple button actions in HTML. Learn when to use submit, button, or reset, why Enter submits, why links (<a>) are best for going to a URL, how formaction switches destinations, and how to label icon buttons.

button 要素

クリックで何かが起きるボタンの作り方を、submit/button/resetの違い・Enterで送信される理由・URL移動は<a>推奨・formactionで送信先切り替え・アイコンボタンの名前付けまで、短いコードとコツで迷わず実装できるようにまとめたページ。

HTML ボタンで実行できるアクション(button action)を中心に、よく使う操作やURLへの移動方法をわかりやすく整理しています。

button 要素とは?

<button> 要素は、ユーザーがクリックすることでアクションを実行するためのボタンを作成します。テキストやアイコンなど、ボタンに表示したい内容をタグの中に書きます。

HTML

<button>Click me</button>

この例では「Click me」という文字が表示されたボタンが作成されます。クリック時の動作は後述の JavaScript で自由に追加できます。

よく使う属性

type 属性

ボタンの動作を決めます。基本は次の3つ:

"submit"(デフォルト)
フォームを送信します。type を省略すると submit になります。
"button"
「クリック時の処理だけ」をしたい通常ボタン。送信させたくないときに使います。
"reset"
同じ <form> 内の入力を、初期値(value など)に戻します。

超重要:フォーム内の <button>書かないと submit です。クリック専用のときは type="button" を必ず付けましょう。

"submit":フォームを送信する(最小の実用例)

必須入力を1つ用意し、送信すると 新しいタブでクエリ(?name=...&agree=on)が見えて「送れた」ことを確認できます。サーバーがなくても動きます。

HTML

<form action="" method="get" target="_blank">
	<label>お名前
		<input name="name" required>
	</label>
	<label>
		<input type="checkbox" name="agree" required> 利用規約に同意
	</label>
	<button type="submit">送信</button>
</form>

送信後に、新しいタブでアドレスバーのURLを見ると、https://yugien.xyz/web/html/button.html?name=Yugien&agree=on#typeSubmit となっており、?name=Yugien&agree=on が増えているので、正しく送信できていることが確認できます。

ポイント:

"button":送信せず、その場の処理だけ行う

同じフォーム内にあっても type="button" なら送信されません。ここでは「確認メッセージのオン/オフ」を切り替える例です。

HTML + JavaScript

<form id="demoButtonForm" action="" method="get" target="_blank">
	<label>メール
		<input name="email" type="email" placeholder="[email protected]">
	</label>

	<!-- 送信しないプレビューボタン -->
	<button type="button" id="previewBtn">プレビュー表示/非表示</button>

	<!-- 実際の送信ボタン -->
	<button type="submit">送信</button>

	<p id="previewBox" hidden>プレビュー:入力内容を確認しました。</p>
</form>

<script>
	(function () {
		const btn = document.getElementById('previewBtn');
		const box = document.getElementById('previewBox');
		if (btn && box) {
			btn.addEventListener('click', function () {
				box.hidden = !box.hidden; // その場で表示のON/OFFを切り替え
			});
		}
	})();
</script>

ポイント

"reset":入力内容を初期値に戻す(確認つき推奨)

value などで指定した「初期値」に戻します。使いどころは限られるため、誤操作防止の工夫(確認や目立たせない配置)をしましょう。

HTML + JavaScript(確認ダイアログ付き)

<form id="demoResetForm">
	<label>お名前
		<input name="name" value="山田太郎">
	</label>

	<label>色の好み
		<select name="color">
			<option>赤</option>
			<option selected>青</option>
			<option>緑</option>
		</select>
	</label>

	<button type="reset" id="resetBtn">入力をクリア</button>
</form>

<script>
	(function () {
		const form = document.getElementById('demoResetForm');
		const btn  = document.getElementById('resetBtn');
		if (form && btn) {
			btn.addEventListener('click', function (e) {
				if (!confirm('入力を初期状態に戻します。よろしいですか?')) {
					e.preventDefault(); // リセットをキャンセル
				}
			});
		}
	})();
</script>

注意reset は同じ <form> 内だけに効きます。他のフォームは対象外です。


まとめ

disabled 属性

ボタンを無効化し、クリックできないようにします。グレー表示になり「同意する」にチェックを入れるまで押せないボタンなどで利用されます。

HTML

<button disabled>送信</button>

注意aria-disabled="true" は見た目や読み上げでは「無効」に聞こえますが、実際にはクリックできます。押せないようにするには disabled を使うか、click イベントで event.preventDefault() などの制御が必要です。

補足disabled にしたボタンは フォーカスできず送信対象にもなりません(name/value も送られません)。

name 属性・value 属性

フォーム送信時に、ボタンが押されたときの名前と値をサーバーに送ります。

HTML

<form action="/submit" method="post">
<button type="submit" name="submit" value="clicked">送信</button>
</form>

補足:サーバーに送られるのは「実際に送信に使われた ボタン」の name=value です。値を確実に扱いたい場合は、value を 明示 しましょう。

HTML ボタンとリンクの違い:URL移動は a、操作は button(button action の基本)

ページ遷移(リンク移動)には <a>、操作(送信・開閉など)には <button> を使います。

見た目が似ていても、役割が異なるため適切なタグを使い分けましょう。

注意:リンクに role="button" を付けてボタンのように見せる方法は、実務ではアンチパターンです。<a href> から href を外したり既定動作を止めてしまうと、中クリックや長押しメニュー、URLコピー、履歴(戻る)など「リンク本来の機能」を失います。遷移には <a href>、その場の操作には <button> を使うのが確実です(意味論の面でも正しい選択です)。

また、abutton互いに入れ子にしません(どちらもインタラクティブ要素のため入れ子は不可・非推奨)。

ページやURLへ「移動」するだけなら <a href> を使うのが基本です。button はページ内の開閉や送信など「その場の操作」を担います。

HTML

<!-- こう書けばOK:遷移は a -->
<a href="/next">次へ</a>

<!-- どうしても button で遷移したいとき -->
<button type="button" onclick="location.href='/next'">次へ</button>

Enterで送信される理由(暗黙の submit

※ 入力欄が1つだけの簡単なフォームでは、送信ボタンが見えていなくても Enter で送信されることがあります(暗黙送信)。送信させたくない場面では、クリック専用ボタンに type="button" を付ける/必要なら入力欄側で Enter を抑止します。

補足Enter キーでの「暗黙送信」は、フォームの構造(入力欄の数や submit ボタンの有無)に左右されます。期待に頼らず、クリック専用ボタンには type="button" を付け、必要なら入力欄で Enter を抑止しましょう。

HTML

<!-- HTML(例):クリック専用ボタンは type="button" を明示 -->
<button type="button" onclick="openPanel()">開く</button>

JavaScript

// JS:対象フォームに限定し、テキスト入力のEnterだけ送信を抑止
const form = document.getElementById('myForm'); // ← 実フォームのIDに置換
if (form) {
	form.addEventListener('keydown', function (e) {
		const t = e.target;
		const isTextArea = t && t.tagName === 'TEXTAREA';
		const isContentEditable = t && t.nodeType === 1 && t.isContentEditable === true;
		const isTextInput =
			t && t.tagName === 'INPUT' &&
			!['button', 'submit', 'reset', 'checkbox', 'radio', 'file', 'range', 'color', 'image', 'hidden'].includes((t.type || '').toLowerCase());

		// IME入力中(かな漢字変換の確定)は isComposing=true なので止めない
		if (!isTextArea && !isContentEditable && isTextInput && e.key === 'Enter' && !e.isComposing) {
			e.preventDefault(); // テキスト入力欄でのEnter送信だけ抑止
		}
	});
}

ポイント:ボタンやリンクにフォーカスがある状態の Enter は既定で“押す”動作になります。上のように対象を絞れば、それらの操作は壊さず、「入力中の誤送信だけ」を防げます。

補足:実務では document 全体ではなく、対象フォーム(例:const form = document.getElementById('myForm'))に絞って form.addEventListener('keydown', ...) とするほうが副作用が少なく安全です。

フォーム内のボタンは既定で type="submit" です。テキスト入力中に Enter を押すと「暗黙の送信」が起きます。クリック用途だけのボタンは type="button" を明示します。

HTML

<button type="button">クリックだけ(送信しない)</button>

ボタンの中に入れて良いもの / ダメなもの

<button> の中に入れられるのは テキストやアイコンなどの「フレージングコンテンツ」 です。

他のボタン・リンク・入力など「別のインタラクティブ要素」を入れるのはNG。思わぬ挙動やアクセシビリティ問題の原因になります。

例:OK(テキスト、<img><svg><span> など)/ NG(<a>、別の <button><input> など「インタラクティブ要素」)。

理由:ボタンの中に別のボタンやリンクを入れると、フォーカスの移動順やクリックの判定が壊れ、スクリーンリーダーなどでは「どれが押せる要素か」が正しく伝わらなくなります。HTML仕様でも「インタラクティブ要素の入れ子は禁止」と定義されており、支援技術やブラウザの動作が不安定になります。

アイコンのみのボタンは 視覚的なラベルがない ので、aria-label="閉じる" のように 意味が伝わるラベルを明示 しましょう。

補足 : title 属性でも補助的に説明できますが、スクリーンリーダーには aria-label を付けるのがより確実です。

ボタンからURLへ移動する最短メモ

遷移に button を使う場合は、最短で下のように書けます(本来は a 推奨)。

注意:この方法は「今のタブで移動」だけです。中クリックや長押しメニュー、URLコピーなどの“リンクらしい操作”はできません。URL遷移は基本的に <a href> を使いましょう。

HTML

<button type="button" onclick="location.href='/next'">次へ</button>

formaction で送信先をボタンごとに切り替え

同じフォームでも、ボタンごとに送信先・メソッド等を変えられます(確認画面/本送信など)。

HTML

<form id="contact" action="/send" method="post">
	<input name="email" required>
	<button type="submit">通常送信</button>
	<button type="submit" formaction="/confirm" formmethod="get" formtarget="_blank">確認画面へ</button>
</form>

フォームの外から送信する(form 属性)

ボタンがフォームの外にあっても、form 属性で対象フォームを指定できます。

HTML

<form id="f1" action="/send" method="post">... </form>
<button type="submit" form="f1">このフォームを送信</button>

CSS で見た目を変更

CSS

button {
	display: inline-block;
	padding: 1ex 2ex;
	margin: 1ex;
	font-size: larger;
	box-shadow: 0.2ex 0.2ex 0.3ex;
}

おすすめ:キーボード操作に優しいよう、:focus-visible のスタイル(アウトライン)を消さずに 見やすく しましょう。button:disabled { cursor: not-allowed; opacity: .6; } のような無効時の見た目を付けるのも有効です。

CSS

button:focus-visible {
	outline: 2px solid blue; /* キーボード操作時に見やすい枠 */
	outline-offset: 2px;
}

このようにしておくと、キーボード操作でもボタンの位置がはっきりわかります。

:focus のアウトラインは消さないのが基本です。どうしても見た目を変えたい場合は、このページのように :focus-visible で「キーボード操作のときだけ見やすく」するのがおすすめです。

JavaScript で動きを追加

onclick 属性でクリック時の動作を指定できます。

実務では、保守性や再利用性のためにインラインの onclick ではなく、外部JSで addEventListener('click', …) を使う方法が推奨されます。

実務のコツ:フォームの中で使うときは、誤送信防止のため type="button" を付けたうえで onclick を使います。

HTML + JavaScript

<button type="button" onclick="myFunction()">クリック</button>

<script>
	function myFunction() {
		alert("ボタンがクリックされました!");
	}
</script>

ポップオーバーを開閉する属性

popovertargetpopovertargetaction は、popover 属性を持つ要素(小さなパネルやメニュー等)を <button> から開閉するための HTML標準の仕組みです。JavaScriptを書かずに「開く/閉じる/トグル」を実現できます。

popovertarget
開閉対象の要素の id を指定します(例:menu)。
popovertargetaction
操作種別を指定します。toggle(既定)/showhide のいずれか。
popover(対象側の属性)
対象要素に付けます。既定は auto で、外側クリックや Esc などで閉じられます。
popover="manual" とすると自動では閉じず、JSや popovertargetaction で制御します。

使いどころ:メニュー/簡易ダイアログ/補助パネル/「詳細」パネルなどの軽量UIに適します。ページ遷移は <a href> を使うのが基本です(このページの方針と同じ)。

HTML

<!-- 開閉ボタン:デフォルトは toggle -->
<button type="button" popovertarget="menu">メニュー</button>

<!-- 対象:小さなパネル -->
<div id="menu" popover>
    <p>メニュー内容…</p>
    <button type="button" popovertarget="menu" popovertargetaction="hide">閉じる</button>
</div>

ポイントtoggle は「開いていれば閉じる/閉じていれば開く」。確実に開きたい・閉じたい場合は show / hide を指定します。

操作を明示する(show / hide)

HTML

<button type="button" popovertarget="tips" popovertargetaction="show">ヘルプを開く</button>
<button type="button" popovertarget="tips" popovertargetaction="hide">ヘルプを閉じる</button>

<div id="tips" popover>
    <p>ここに補助説明。外側クリックでも閉じられます。</p>
</div>

ここに補助説明。外側クリックでも閉じられます。

自動で閉じさせない(manual モード)

モーダル風に「明示操作でしか閉じてほしくない」ケースでは、popover="manual" を使います。

HTML + JavaScript

<button type="button" id="openDialog">詳細を開く</button>
<div id="dialog" popover="manual">
    <h4>詳細設定</h4>
    <button type="button" id="closeDialog">閉じる</button>
</div>

<script>
    // Progressive Enhancement(対応環境のみ実行)
    const dlg = document.getElementById('dialog');
    const openBtn = document.getElementById('openDialog');
    const closeBtn = document.getElementById('closeDialog');

    const canPopover = typeof HTMLElement !== 'undefined'
        && 'showPopover' in HTMLElement.prototype;

    if (canPopover && dlg && openBtn && closeBtn) {
        openBtn.addEventListener('click', () => dlg.showPopover());
        closeBtn.addEventListener('click', () => dlg.hidePopover());
    }
</script>

詳細設定

スタイリングの最小メモ

[popover] は通常の要素なので、背景・影・位置などを自由に装飾できます(必要なら絶対配置)。

CSS

[popover] {
    padding: 1em;
    box-shadow: 0 2px 8px rgba(0,0,0,.2);
    border-radius: .5em;
    max-inline-size: 28rem;
}

実務メモ(Do / Don’t)

よくあるつまずき

対象に popover を付け忘れて反応しない
対象側(開閉される要素)に popover が必要です。
id の誤りで開かない
popovertargetid と一致させます(# は不要)。
自動で閉じない/勝手に閉じる
popover="manual" は自動で閉じません。既定(auto)は外側クリック等で閉じます。
未対応環境で崩れる
JSで機能検出して分岐すると安全です(上の例を参照)。

二重送信を防ぐ小ワザ

連打で重複送信しないよう、クリック直後にボタンを一時的に無効化し、送信自体は既定動作に任せます(サーバー側でもトークン等で対策すると万全)。

HTML

<!-- こうすればOK:無効化だけ行い、送信は既定動作に任せる -->
<button type="submit" onclick="this.disabled=true;">送信</button>

ポイント:この方法なら required などのフォーム検証submit イベントがそのまま働きます。JavaScriptで form.submit() を呼ぶと検証やイベントを飛ばすことがあるため、既定の送信に任せるのが安全です。

画面遷移しない場合の再有効化

送信後に同ページで完結する設計(非同期送信・SPAなど)の場合は、サーバー応答後にボタンを再び有効化しましょう。

HTML + JavaScript

<form id="contact" action="/submit" method="post">
    <input name="email" required>
    <button id="sendBtn" type="submit" onclick="this.disabled=true;">送信</button>
</form>

<script>
    const form = document.getElementById('contact');
    const btn  = document.getElementById('sendBtn');

    // 既定の送信を止めずに、送信後の再有効化だけ責務を持つ想定
    form.addEventListener('submit', function () {
        // 非同期送信などでページ遷移しないケースを想定
        fakeApi().then(() => {
            // 正常終了後に再び押せるようにする
            if (btn) btn.disabled = false;
        }).catch(() => {
            // エラー時もユーザーが再試行できるようにする
            if (btn) btn.disabled = false;
        });
    });

    function fakeApi() {
        return new Promise(resolve => setTimeout(resolve, 1000));
    }
</script>

補足:ページ遷移が発生する(通常の同期送信)なら、再有効化は不要です。フォーム検証でエラーがある場合は送信されず、そのままブラウザの検証UI(メッセージ表示やエラー欄へのフォーカス移動)が働きます。

ボタン関連の補助属性(一覧)

formaction
このボタンだけ送信先URLを変更
formmethod
このボタンだけ送信方法(GET/POST など)
formtarget
このボタンだけ別タブ等へ送信(例:_blank
formenctype
このボタンだけエンコード方式(例:multipart/form-data
formnovalidate
このボタンだけ入力チェックをスキップ
autofocus
ページ読込時に自動フォーカス。使いどころは限定的(予期しないスクロールや読み上げ開始の原因になり得る)。

豆知識formaction / formmethod / formtarget / formenctype / formnovalidate は、基本的に type="submit" のボタンに意味があります。

特に formenctypePOST のときだけ有効です。(JS で送信を統一する場合は、後述の form.requestSubmit() を使うと「どのボタンが押されたか」に応じた送信ができます。)

よくあるエラー早見表

押してないのにEnterで送信される
原因:フォーム内ボタンの既定が submit。対処:クリック用途は type="button" を明示。
URLに移動したいだけなのにJSが必要になった
原因:button を使っている。対処:遷移は <a href> を基本に。
送信先だけ別URLにしたい
対処:そのボタンに formaction(必要なら formmethod / formtarget)。
ボタンが“押せない”
原因:disabled が付いている/重なりでクリックを奪われている。対処:属性確認とCSSの重なり(z-index, pointer-events)確認。
スクリーンリーダーで意味が伝わらない
原因:アイコンだけでラベルなし。対処:aria-label か視覚的に隠したテキストを追加。
連打で二重送信される
対処:クリック直後に this.disabled=true を入れる/サーバー側でも重複防止トークン。
検証が効かない・submitイベントが発火しない
原因:JSで form.submit() を呼んでいる。対処:form.requestSubmit() を使う。
見た目は無効なのにボタンが押せてしまう
原因:aria-disabled だけでJS抑止がない。対処:disabled を使う/clickpreventDefault()
リンクみたいなボタンが使いにくい
原因:URL遷移を button + JS で実装。対処:遷移は <a href> に。

アクセシビリティ(誰でも使えるボタンに)

見た目は同じでも、人によって操作のしかた・見え方は違います。HTMLで意味を作り、必要なところだけARIAで補助情報を足すと、読み上げやキーボード操作でも使いやすくなります。

アイコンだけのボタンにラベルをつける

見た目がアイコンだけでも、音声読み上げに名前を伝えます。

HTML

<button type="button" aria-label="閉じる">✕</button>

トグル状態を伝える(aria-pressed

トグル(ON/OFF)ボタンのように状態を表すときは、aria-pressed を使います。

HTML

<button type="button" aria-pressed="false" id="muteBtn">ミュート</button>
<script>
	const b = document.getElementById("muteBtn");
	b.addEventListener("click", () => {
		const on = b.getAttribute("aria-pressed") === "true";
		b.setAttribute("aria-pressed", String(!on));
	});
</script>

disabledaria-disabled の使い分け

disabled はフォーカス不可・クリック不可・送信対象外です。見た目だけ無効風にしたい(条件で有効化する等)なら aria-disabled="true" を使い、JavaScriptで実際の動作を制御します。

HTML

<!-- 完全に無効 -->
<button type="button" disabled>処理中...</button>

<!-- 見た目だけ無効(キー操作は無効化するJSが別途必要) -->
<button type="button" aria-disabled="true">準備中</button>

注意aria-disabled="true" は見た目や読み上げでは「無効」に聞こえますが、実際にはクリックできます。押せないようにするには disabled を使うか、click イベントで event.preventDefault() などの制御が必要です。キーボード操作(Enter/Space)も同様に抑止してください。

キーボード操作・フォーカスの最小ルール

FAQ

Q. Enterを押すと勝手に送信されるのは?
A. 多くのフォームで暗黙送信が起きます。クリック専用は type="button" を付け、送信ボタンは1つに絞ると安全です。必要なら keydownEnter を抑止します。
Q. URLに移動したいだけなら?
A. <a href>が基本です。<button>+JS だとリンクの便利機能が失われやすいです。
Q. ボタンごとに送信先を変えたい
A. type="submit" のボタンに formaction(必要に応じて formmethod/formtarget)を付けます。
Q. アイコンだけのボタンって大丈夫?
A. aria-label で意味を明示しましょう(例:閉じる)。
Q. 無効風に見せたいけど押せないようにしたい
A. 使えるときはdisabled 一択aria-disabled は見た目/読み上げ用なので、JSでクリック抑止が必要です。
Q. 二重送信を避ける方法は?
A. クリック直後にいったん無効化し、送信はブラウザの既定動作に任せるのが安全です(検証や submit イベントも自然に動きます)。JSで送信を統一したい場合のみ、type="button" + form.requestSubmit() を使います。

「押されたボタン」の設定を効かせつつ送信

JavaScript

<form id="contact" action="/send" method="post">...</form>
<button type="submit" id="sendA" formaction="/a">Aへ送信</button>
<button type="submit" id="sendB" formaction="/b">Bへ送信</button>

<script>
	// どのボタン相当で送信するかを明示できる:requestSubmit(button)
	const form = document.getElementById('contact');
	document.getElementById('sendA').addEventListener('click', (e) => {
		e.preventDefault();              // 既定送信を止める
		form.requestSubmit(e.currentTarget); // sendAの設定(formactionなど)で送信
	});
	document.getElementById('sendB').addEventListener('click', (e) => {
		e.preventDefault();
		form.requestSubmit(e.currentTarget); // sendBの設定で送信
	});
</script>
ポイントform.submit() は検証や submit イベントを飛ばすのに対し、requestSubmit(button) はブラウザの通常フロー(検証・イベント)を通し、かつ “そのボタンの属性” を効かせられるので安全です。