基礎

JavaScriptのpreventDefault入門|ブラウザのデフォルト動作を制御する方法

preventDefault() は、ブラウザがイベントに対して行うデフォルトの動作をキャンセルするメソッドです。リンクのページ遷移、フォームの送信、右クリックメニューの表示など、ブラウザが自動的に行う処理を止めて、JavaScript独自の処理に置き換えたいときに使います。

この記事では、preventDefault() の基本的な使い方から、よく使われるユースケース、stopPropagation() との違いまで解説します。

基本的な使い方

イベントハンドラの引数として受け取るイベントオブジェクトの preventDefault() メソッドを呼び出すことで、デフォルト動作をキャンセルできます。

JavaScript
// リンクのデフォルト動作(ページ遷移)を止める
const link = document.querySelector('#myLink');

link.addEventListener('click', function(e) {
  e.preventDefault();  // ページ遷移をキャンセル
  console.log('リンクがクリックされました');
  console.log('遷移先URL:', this.href);
  // 独自の処理を実行
  showModal(this.href);
});
実行結果
リンクがクリックされました
遷移先URL: https://example.com/page

上記の例では、リンクをクリックしてもページ遷移は行われず、代わりに console.log とモーダル表示の処理が実行されます。preventDefault() を呼ばなければ、通常通りリンク先に遷移します。

フォーム送信のカスタマイズ

preventDefault() が最もよく使われるのは、フォームの送信処理です。デフォルトの送信を止めて、JavaScriptでバリデーションやAjax送信を行います。

JavaScript
const form = document.querySelector('#contactForm');

form.addEventListener('submit', function(e) {
  e.preventDefault();  // フォームのデフォルト送信を止める

  // バリデーション
  const name = form.querySelector('#name').value.trim();
  const email = form.querySelector('#email').value.trim();
  const errors = [];

  if (name === '') {
    errors.push('名前を入力してください');
  }
  if (email === '' || !email.includes('@')) {
    errors.push('正しいメールアドレスを入力してください');
  }

  if (errors.length > 0) {
    console.log('エラー:', errors.join(', '));
    return;
  }

  // バリデーション通過後、Ajax送信
  console.log('送信データ:', { name, email });
  fetch('/api/contact', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ name, email })
  })
  .then(response => response.json())
  .then(data => console.log('送信成功:', data))
  .catch(error => console.log('送信失敗:', error));
});
実行結果
// 名前が空の場合
エラー: 名前を入力してください

// 正常送信の場合
送信データ: { name: '田中太郎', email: 'tanaka@example.com' }
送信成功: { status: 'ok' }

preventDefault() を使わないと、submit イベント発火後にブラウザがフォームを同期的に送信し、ページがリロードされてしまいます。SPA(シングルページアプリケーション)やAjax通信を行う現代のWebアプリでは、ほぼ必ずフォームの submitpreventDefault() を使います。

その他のユースケース

JavaScript
// チェックボックスのチェック/アンチェックを条件付きで防止
const checkbox = document.querySelector('#agreeCheckbox');
checkbox.addEventListener('click', function(e) {
  if (!confirm('本当に変更しますか?')) {
    e.preventDefault();  // キャンセルしたら変更を防止
  }
});

// テキスト入力の制限(数字以外を入力不可)
const numberInput = document.querySelector('#numberOnly');
numberInput.addEventListener('keydown', function(e) {
  const allowed = ['Backspace', 'Tab', 'ArrowLeft', 'ArrowRight', 'Delete'];
  if (!allowed.includes(e.key) && (e.key < '0' || e.key > '9')) {
    e.preventDefault();
    console.log('数字以外は入力できません');
  }
});

// ドラッグ&ドロップのデフォルト動作を止める
const dropZone = document.querySelector('#dropArea');
dropZone.addEventListener('dragover', function(e) {
  e.preventDefault();  // これがないとdropイベントが発火しない
  this.classList.add('drag-over');
});

dropZone.addEventListener('drop', function(e) {
  e.preventDefault();
  this.classList.remove('drag-over');
  const files = e.dataTransfer.files;
  console.log('ドロップされたファイル:', files.length + '件');
});

ドラッグ&ドロップでは dragoverpreventDefault() が特に重要です。これを呼ばないと、ブラウザがファイルを直接開こうとし、drop イベントが発火しません。

stopPropagation との違い

JavaScript
// preventDefault: ブラウザのデフォルト動作を止める
// stopPropagation: イベントの伝搬(バブリング)を止める

document.querySelector('#parent').addEventListener('click', function() {
  console.log('親要素がクリックされた');
});

document.querySelector('#child-link').addEventListener('click', function(e) {
  e.preventDefault();      // リンク遷移を止める(デフォルト動作)
  e.stopPropagation();     // 親要素への伝搬を止める(バブリング)
  console.log('子要素のリンクがクリックされた');
});
実行結果
// #child-link をクリックした場合
子要素のリンクがクリックされた
// 親要素のハンドラは実行されない
defaultPrevented プロパティ

イベントオブジェクトの e.defaultPrevented プロパティを使うと、他のハンドラで preventDefault() が呼ばれたかどうかを確認できます。複数のイベントハンドラが設定されている場合の協調動作に便利です。

passive イベントリスナーでは使えない

addEventListener の第3引数で { passive: true } を指定すると、preventDefault() が無効になります。スクロール系イベント(touchstartwheel)ではパフォーマンス向上のためにブラウザが自動的に passive にする場合があります。preventDefault() を使いたい場合は { passive: false } を明示してください。

まとめ

  • e.preventDefault() はブラウザのデフォルト動作(リンク遷移、フォーム送信など)をキャンセルする
  • フォームの submit イベントで使い、Ajax送信やバリデーションに置き換えるのが定番
  • ドラッグ&ドロップでは dragoverpreventDefault() が必須
  • stopPropagation() はイベントの伝搬を止めるもので、preventDefault() とは別の機能
  • passive リスナーでは preventDefault() が無効になる点に注意