HTMLのフォーム送信がEnterキーなのか送信ボタンなのか判別する方法

HTMLのフォームは、送信ボタン（`<button type="submit">`）をクリックするだけでなく、[暗黙の送信手段](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#implicit-submission)による送信もサポートされています。大抵のウェブブラウザでは、フォームの入力欄（inputやtextarea）で**Enterキー**を押すことで、送信ボタンを押さなくても送信できる挙動をサポートしており、これが暗黙の送信に該当します。

この記事では、理由はともかく、**フォームの送信（submitイベント）がEnterキーによって起きた（暗黙の送信）のか送信ボタンを押したことで起きたのかを判定したい**人に向けてその方法を伝授します。

## TL;DR

暗黙の送信用の見えない送信ボタンと、ユーザーが押す用の見える送信ボタンを用意しましょう。

## 解説

Enterキーのような方法による暗黙の送信は、実際には「そのフォームの**default button**に対して`click`イベントを発生させる」という機構によって発生しています。

そして、実はフォームは複数の送信ボタンを持つことができ、その場合にどの送信ボタンが押されたのか判別できる仕組みを持っています。

これを組み合わせることで、暗黙の送信で押されるボタン（default button）と、ユーザーが明示的に押すボタンを別々にすることで、どちらのボタンが押されたのか判別することができます。

実際のHTMLはこのようにします。

```html
<form onsubmit="handleSubmit(event)">
  <p><input placeholder="入力欄でEnterを押して送信"></p>
  <button hidden type="submit" name="enter"></button>
  <p><button type="submit" name="submitbutton">送信ボタン</button></p>
</form>
```

![HTMLをブラウザで表示したところの画像。入力欄と送信ボタンが見える。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233667/ec64fbee-f77b-b4d6-125f-1e1c2e9e94d8.png)


ポイントは、`type="submit"`のボタンが2つあることです。お察しのとおり、1つが暗黙の送信用で、もう1つがユーザーに見える送信ボタンです。暗黙の送信用は見えなくてもいいので`hidden`属性がついています。

暗黙の送信時に使われるdefault buttonは「そのフォームに属する最初の送信ボタン」であると定義されているので、ユーザーに見える送信ボタンよりも前に配置することでこちらがdefault buttonになります。

送信時（submitイベントの処理）はこのように書きます。

```js
function handleSubmit(event) {
  event.preventDefault();
  // event.submitterに送信ボタンの要素が入っている
  const submitterName = event.submitter.name;
  alert(`submit ${submitterName}`);
}
```

ポイントは、`event`（[SubmitEvent](https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent)）の[submitter](https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent/submitter)プロパティであり、どの送信ボタンが押されたのかを得ることができます。

今回はどの方法で送信されたのかをalertで表示することにしました。次のように、入力欄でEnterを押した場合と送信ボタンを押した場合で異なる内容が表示されます（Google Chromeで確認）。

入力欄でEnterを押した場合:

![「submit enter」と表示されているアラートの画像。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233667/58a0a251-b9cf-3ae3-3df0-bea670ef89cc.png)

送信ボタンを押した場合:

![「submit submitbutton」と表示されているアラートの画像。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233667/25c24585-e99a-3563-3eca-888e03a0c96f.png)

これで、フォームがEnterキーで送信されたのか送信ボタンのクリックで送信されたのかを判別することができました。

実際に試すことができるCodePenも用意しました。挙動を確かめてみましょう。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="VwJvVbw" data-pen-title="Untitled" data-user="uhyo" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/uhyo/pen/VwJvVbw">
  Untitled</a> by uhyo (<a href="https://codepen.io/uhyo">@uhyo</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

なお、このテクニックを使用する場合はアクセシビリティにも気を付けてください。上記のHTMLのように前者をhidden属性で隠していれば大丈夫のはずですが、HTML上2つの送信ボタンを配置することになるため、支援技術のユーザーから無駄に送信ボタンが2つ見えるといった状態は避けるようにしましょう。

また、この記事ではクライアントサイドでの判別方法を説明しましたが、formの送信をクライアント側で止めずにサーバーへリクエストを送るという場合でも、サーバー側でどの送信ボタンが押されたのかを判別することができます（詳細は省略）。

## 結論

フォームの送信方法を判別したい機会はあまり無いと思いますが、もしあった場合はこの記事を参考にしてください。