Form 中の Input にフォーカスがあたっているとき enter を押すと Button のクリックイベントが発生してからサブミットイベントが発生する場合がある

ふとしです。

SPA をつくっていると onSubmit に処理に送信処理を書いていますが、ボタンのクリックイベントを経由してしまうことに長い間気づいていたなかったのでメモとして残します。

状況

フォームにインプットといくつかのボタンがあり、送信時には onSubmit が呼ばれて欲しいという状況です。

<form id="form">
  <div><input type="text" /></div>
  <ul>
    <li>
      <button id="b1" type="button">button 1</button>
    </li>
    <li>
      <button id="b2">button 2</button>
    </li>
    <li>
      <button id="b3">button 3</button>
    </li>
  </ul>
</form>
function onSubmit (e) {
  e.preventDefault();
  console.log('submit');
}

function onClick (e) {
  console.log('click:', e.target.innerText);
}

document
    .querySelector('#form')
    .addEventListener('submit', onSubmit);

['#b1', '#b2', '#b3'].forEach((id) => {
  document
      .querySelector(id)
      .addEventListener('click', onClick);
});

結果

上のコードでインプットにフォーカスがあたった状態で enter を押すと以下のようなログが得られます。

click: button 2
submit

type="button" を忘れるこうなる

Button タグは明示的に type を与えないと type="submit" として扱われます。そのため、もっとも最初に出現した button をクリックしたとしての処理の順序になりました。

送信時に起こってほしくない操作を Button に付与している場合、必ず type="button" をつけましょう、という話でした。