A safe, universal way to react when something is “pressed”—mouse, tap, or keyboard—so you can switch views, open menus, or stop a submit right after the user’s action.
ボタンやリンクを「押した合図」を受け取り、画面の切り替え・送信の中止・メニューの開閉など“押した後に起きてほしいこと”を、マウス・タップ・キーボードの操作を含めて安全に実装できる仕組み。
まずイメージから。
「マウスでポチッ」「スマホでトン」「Enterキーで決定」──これらが“クリック”として扱われ、ボタンやリンクを“動かす合図”になります。JavaScriptでは、この合図(イベント)を受け取って、画面を書き換えたり、メニューを開いたり、送信を止めたりできます。
element.addEventListener('click', handler)onclick="..." はメンテしづらいclickは来る(指のタップでOK)<button>や<a>など)event.preventDefault()、伝播を止めたいときは event.stopPropagation()HTML
<button id="buy">Buy</button>
<script>
const btn = document.getElementById('buy');
btn.addEventListener('click', (e) => {
console.log('買うボタンが押されました!', e);
// ここで購入処理など
});
</script>
onclick="..."(HTML属性)element.onclick = handler(プロパティ)element.addEventListener('click', handler, options)(推奨)once/signalなどモダンな機能が使える。JavaScript
const handler = (e) => console.log('clicked!');
document.querySelector('#btn').addEventListener('click', handler, { once: true });
clickは「要素のアクティベーション(活性化)」に紐づくイベントです。要素の種類ごとに既定動作(リンクの遷移、ボタンの送信、フォーカス移動など)があり、ユーザー操作やスクリプトからのclick()呼び出しで発火します。キーボードが“クリック相当”になるかは要素次第(例:<button>はEnter/Space、<a>はEnterが相当)です。<div>にclickだけ付けるのはNG。<button><a href="..."><div>にしたいときの最低限(推奨はしない)
tabindex="0" を付けてフォーカス可能にrole="button" で意味を伝えるkeydownでEnterとSpaceを拾い、click()を呼ぶHTML
<div id="like" role="button" tabindex="0" aria-pressed="false">Like</div>
<script>
const el = document.getElementById('like');
const toggle = () => {
const pressed = el.getAttribute('aria-pressed') === 'true';
el.setAttribute('aria-pressed', String(!pressed));
};
el.addEventListener('click', toggle);
el.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault(); // Spaceでページがスクロールするのを防ぐ
toggle();
}
});
</script>
event.stopPropagation() … 以降の親へ伝わらないevent.stopImmediatePropagation() … 同じ要素に付いた他のハンドラも止めるHTML
<ul id="list">
<li data-id="1">A</li>
<li data-id="2">B</li>
<li data-id="3">C</li>
</ul>
<script>
const list = document.getElementById('list');
list.addEventListener('click', (e) => {
const li = e.target.closest('li');
if (!li || !list.contains(li)) return;
console.log('クリックされたID:', li.dataset.id);
});
</script>
preventDefault()は既定の“後始末”や“遷移”を止める合図。<a>のページ遷移、<form>の送信、<label>のフォーカス移動など。HTML
<a id="toAbout" href="/about">About</a>
<script>
document.getElementById('toAbout').addEventListener('click', (e) => {
e.preventDefault();
// pushStateしてAJAXロードなど
history.pushState({}, '', '/about');
// コンテンツ差し替え処理
});
</script>
注意:止める必要のない場所でpreventDefault()を多用しない。操作性や支援技術に悪影響が出る。
<button>disabledだとclickは発火しない。type="submit"はフォーム送信が既定動作。<a href>hrefがないとリンクとしての意味が薄れ、支援技術での扱いも変わる。<label for="id">label内のクリックは、実際の入力要素にも影響する(処理の重複に注意)。disabledなフォーム部品contenteditableや選択可能なテキストpreventDefault()は避けたい。dblclickcontextmenuauxclickpointerup/pointerdown / mouseup/mousedownelement.click()dispatchEvent(new MouseEvent('click'))event.isTrustedで“本当にユーザー操作か”判定可能(click()やdispatchEventで発火したイベントは通常false)。JavaScript
const controller = new AbortController();
button.addEventListener('click', onClick, {
capture: false, // 先に親→子で拾うならtrue
once: true, // 一度だけ実行して自動解除
passive: false, // clickでは通常メリット薄い(touch/wheel向け)
signal: controller.signal // 中断で一括解除
});
// 必要になったら controller.abort();
onceは“おみくじボタン”のように“一回きり”に最適。signalは複数リスナをまとめて外すときに強力(クリーンアップが簡単)。event.target / event.currentTargetclosest()と組み合わせるのが定番。event.detailevent.button / event.buttonsevent.composedPath()event.isTrustedtrue。自動実行やテスト合成ではfalse。labelとinputの両方にリスナを置いて重複実行stopPropagation()や処理の場所整理、closest()でターゲットを限定<meta name="viewport" content="width=device-width, initial-scale=1"> を基本に。disabledにクリック付けたのに動かない」disabled要素はクリック不可。ラッパーや別UIで扱う。JavaScript
const modal = document.getElementById('modal');
const overlay = document.getElementById('overlay');
overlay.addEventListener('click', () => closeModal());
// モーダル内をクリックしても閉じない
modal.addEventListener('click', (e) => e.stopPropagation());
HTML
<button id="menuBtn" aria-expanded="false" aria-controls="menu">Menu</button>
<nav id="menu" hidden>...</nav>
<script>
const btn = document.getElementById('menuBtn');
const menu = document.getElementById('menu');
const open = () => {
btn.setAttribute('aria-expanded', 'true');
menu.hidden = false;
document.addEventListener('click', onOutside, { signal: outsideController.signal });
};
const outsideController = new AbortController();
const onOutside = (e) => {
if (e.target.closest('#menu') || e.target.closest('#menuBtn')) return;
close();
};
const close = () => {
btn.setAttribute('aria-expanded', 'false');
menu.hidden = true;
outsideController.abort(); // outsideリスナを一括解除
};
btn.addEventListener('click', () => {
const expanded = btn.getAttribute('aria-expanded') === 'true';
expanded ? close() : open();
});
</script>
HTML
<a href="/settings" id="toSettings">Settings</a>
<main id="app"></main>
<script>
document.getElementById('toSettings').addEventListener('click', (e) => {
e.preventDefault();
history.pushState({}, '', '/settings');
document.getElementById('app').textContent = 'Settings Page';
});
</script>
JavaScript
document.getElementById('buy').addEventListener('click', async (e) => {
e.currentTarget.disabled = true;
try {
await purchase();
} finally {
e.currentTarget.disabled = false;
}
}, { once: true });
HTML
<ul id="actions">
<li><button data-action="edit">Edit</button></li>
<li><button data-action="delete">Delete</button></li>
</ul>
<script>
document.getElementById('actions').addEventListener('click', (e) => {
const btn = e.target.closest('button[data-action]');
if (!btn) return;
const action = btn.dataset.action;
if (action === 'edit') editItem();
if (action === 'delete') deleteItem();
});
</script>
JavaScript
document.getElementById('play').addEventListener('click', (e) => {
if (!e.isTrusted) return; // 自動実行やbotを弾く
video.play();
});
once、AbortController、画面遷移時のクリーンアップ)。<button>と<a>)。アクセシビリティ最優先。preventDefault/stopPropagationの乱用は保守性低下)。addEventListener('click', ...)が基本。closest()で賢く拾う。preventDefault()。once/signalでライフサイクル管理。element.click()とdispatchEvent(...)は目的で使い分け。