HTMXを活用して簡単に実装するHTMLお問い合わせフォーム

# はじめに

57歳で製造業からWeb開発企業に転職して、やっと2年目に突入したピータンと申します。

Web制作者の方が作るランディングページにはかならずといってお問い合わせフォーム（コンタクトフォーム）がありますが、これを最近、気になっている[HTMX](https://htmx.org/)を使ったら、どのくらい簡単にできるのか実験してみました。

結果的には、HTMLに対して、3行ほど、HTMXに関する記述を追加、変更するだけでフロントエンド側が完了しました。とても簡潔で良いなと思いました。ただし、バックエンドをどうするかの問題はあります。CSSも少し必要です。

# 完成品

お問い合わせを内容をメールで通知したり、SlackやDiscordに流すこともできるのでしょうが、今回はGoogleスプレッドシートに格納する方式としました。

![animation](https://github.com/pitang1965/contact-form/assets/47315420/c7fa87be-a989-40ca-b2ba-0cea654cc4fc)

# HTMLのポイント

次のように追加、変更しました。

```html:index.html
    <script src="https://unpkg.com/htmx.org@1.9.10"></script>
```
これを書くだけでHTMXが使えるようになります。

```html:index.html
      <form
        id="contact"
        hx-post="/api/submit"
        hx-target="#submit-button"
        hx-swap="outerHTML"
      >
```
これにより、`<form>`のSubmitボタン（今回は[送信]ボタン）がクリックされたら、`/api/submit`という相対パス指定されたAPIのエンドポイントに、問い合わせ内容を送信（POST）し、返却されたHTMLで、[送信]ボタンを置き換えます。具体的には、[送信]が、「送信されました。ピータンさん。お問い合わせありがとうございます。」に変わり、ボタンが押せなくなります。

```html:index.html
        <div class="htmx-indicator loader"></div>
```

上記の1行で、APIが処理を終えるまでの間にローディングアニメーションを表示します。今回は`loader`というCSSクラスで定義したCSSのローディングアニメーションを使用していますが、SVGファイルなども指定可能です。

`index.html`の全体は次になります。

```html:index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>お問い合わせフォーム</title>
    <link rel="stylesheet" href="/style.css" />
    <link rel="icon" type="image/svg+xml" href="/logo.svg" />
    <script src="https://unpkg.com/htmx.org@1.9.10"></script>
  </head>
  <body>
    <div class="container">
      <form
        id="contact"
        hx-post="/api/submit"
        hx-target="#submit-button"
        hx-swap="outerHTML"
      >
        <h3>お問い合わせフォーム</h3>
        <h4>ご意見・ご要望をお寄せください。</h4>
        <fieldset>
          <input
            placeholder="お名前"
            type="text"
            name="name"
            tabindex="1"
            required
            autofocus
          />
        </fieldset>
        <fieldset>
          <input
            placeholder="メールアドレス"
            type="email"
            name="email"
            tabindex="2"
            required
          />
        </fieldset>
        <fieldset>
          <input
            placeholder="電話番号（任意）"
            type="tel"
            name="tel"
            tabindex="3"
          />
        </fieldset>
        <fieldset>
          <input
            placeholder="会社名（任意）"
            type="text"
            name="company"
            tabindex="4"
          />
        </fieldset>
        <fieldset>
          <textarea
            placeholder="メッセージをこちらにどうぞ...."
            type="text"
            name="message"
            tabindex="5"
            required
          ></textarea>
        </fieldset>
        <button name="submit" type="submit" id="submit-button">送信</button>
        <div class="htmx-indicator loader"></div>
        <p class="copyright">
          Powered by
          <a
            href="https://over40web.club"
            target="_blank"
            title="Over 40 Web Club"
            >Over 40 Web Club</a
          >
        </p>
      </form>
    </div>
  </body>
</html>

```

# 追加の説明

今回の実装において、HTMXに関連して`index.html`に3つのタグの追加、変更を追加することを説明しましたが、他にも留意することがあります。Googleスプレッドシートに結果を格納するバックエンドのコードはもちろん必要になりますが、フロント側についてまず説明します。

HTML側が気にすぺきポイントは、今回のバックエンドのコードに依存し、次になります。

バックエンドのコードは、`index.html`が以下の`name`属性を持つことを前提にしています。
  * name
  * email
  * tel
  * company
  * message

また、`<form>`タグで指定している`submit-button`という`id`属性を持つ要素が必要です。

バックエンドのコードは、次のいずれかの形式のHTMLを返却します（正常時又はエラー時）

```html
<button disabled id="api-success">送信されました。${name}さん、お問い合わせありがとうございます。</button>

又は

<button disabled id="api-error">エラーのため送信できませんでした。申し訳ございません。${error}</button>
```

このため、上記の２つのCSSクラス`api-success`と`api-error`に対して、CSS（エラーの場合は赤字にするなど）を書くことになります。

今回は、`<form>`タグで`hx-post="/api/submit"`と設定していますが、お問い合わせフォームと異なるドメインのAPIが、そのドメイン外からの使用を許可していれば、`hx-post="https://abc.com/contact"`みたいな感じで絶対パスを設定することも可能です。

バックエンドは、[Express](https://expressjs.com/ja/)というNode.jsのWebフレームワークを用い、[Google Sheets API](https://console.cloud.google.com/apis/library/sheets.googleapis.com?hl=ja)を使用して、Googleスプレッドシートに格納しています。

また、全体を[Vercel](https://vercel.com/)にデプロイし、APIはサーバレスファンクションで動かすために、`/api`フォルダ以下に格納し、`vercel.json`というファイルを置いています。

* [Using Express.js with Vercel](https://vercel.com/guides/using-express-with-vercel)

コード全体は、[GitHub](https://github.com/pitang1965/contact-form)を参照願います。また、よろしければ、次の関連記事も参照していただければと思います。

# 関連記事
* [HTMXとGemini APIを用いて簡単なチャットアプリを作ってみた](https://qiita.com/pitang1965/items/e1000e2025a64d1125f6)