# HTML フォーム

> JavaScript なしで、どんな HTML フォームでも Ikiform に送信できます。リダイレクト、予約済みフィールド、配列、ハニーポットについて説明します。

プレーンな HTML フォームだけで連携は完了です。スクリプトも iframe も埋め込みも不要です。`action` にフォームのエンドポイントを設定し、マークアップと CSS はそのまま使います。カスタム HTML を貼り付けられるサイトビルダーでも使えます。[サイトビルダー](https://ikiform.com/ja/docs/guides/site-builders.md)を参照してください。

## 基本のフォーム

`contact.html`:

```html
<form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
  <label>
    Name
    <input name="name" autocomplete="name" required />
  </label>
  <label>
    Email
    <input name="email" type="email" autocomplete="email" required />
  </label>
  <label>
    Message
    <textarea name="message" rows="5"></textarea>
  </label>
  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
  <button>Send</button>
</form>
```

- `method` は `post` にする必要があります。ブラウザーは `application/x-www-form-urlencoded` を送り、`enctype` を設定した場合は `multipart/form-data` を送ります。どちらでも動きます。
- `name` を持つコントロールはすべてフィールドになります。名前のないコントロールや無効化されたコントロールは、ブラウザーから送信されません。
- 値は UTF-8 のテキストとして保存され、NFC に正規化され、CRLF の改行は LF に変換され、制御文字は削除されます。
- `required` や `type="email"` などのブラウザーでのバリデーションは入力する人の助けにはなりますが、セキュリティチェックではありません。サーバーで Ikiform にルールを適用させるには、[フィールド](https://ikiform.com/ja/docs/fields.md)を定義してください。

## 送信後

ブラウザーからの送信が成功すると、`303` リダイレクトで応答します。Ikiform は次の順番でリダイレクト先を選びます:

1. ダッシュボードのフォームの **Redirect after submit**（送信後のリダイレクト）設定。ワークスペースのメンバーしか設定できないため、`http:` でも `https:` でも任意の URL を使えます。
2. 送信に含まれる `_redirect`（または `_next`）フィールド。下記のルールを満たす場合に限ります。
3. それ以外の場合は、`/f/<formId>/thanks` にある Ikiform のホストされたサンクスページ。フォームに許可ドメインがあり、そのいずれかの `https:` ページから送信された場合、サンクスページにはそのページへ戻るリンクが表示されます。

### _redirect のルール

`_redirect` の値は訪問者のブラウザーから送られるため、Ikiform がそれに従うのは、ユーザー名、パスワード、独自ポートのない `https:` の URL で、フォームの許可ドメインまたはそのサブドメイン上にある場合だけです。許可ドメインのないフォームは `_redirect` を完全に無視します。許可ドメインが `example.com` の場合:

| _redirect | リダイレクトする | 理由 |
| --- | --- | --- |
| `https://example.com/thanks` | はい | 許可ドメイン |
| `https://app.example.com/done` | はい | 許可ドメインのサブドメイン |
| `http://example.com/thanks` | いいえ | `https:` ではない |
| `https://example.com:8443/thanks` | いいえ | 独自ポート |
| `https://user@example.com/` | いいえ | ユーザー名を含む |
| `https://example.com.evil.dev/` | いいえ | そのドメインでもサブドメインでもない |

従わなかった `_redirect` は、ホストされたサンクスページへのリダイレクトになります。エラーになることはありません。JSON のリクエストはリダイレクトを無視し、送信 ID 付きの `201` を受け取ります。

### 送信が拒否された場合

必須フィールドがないなどの理由で送信が拒否されると、ブラウザーにはエラーの HTTP ステータスでホストされたエラーページが表示されます。問題点をフィールドのラベルごとに一覧にし、フォームへ戻るリンクを表示します。すべてのコードは[エラー](https://ikiform.com/ja/docs/errors.md)を参照してください。

## フィールド名と配列

同じ名前が繰り返される場合や、名前が `[]` で終わる場合は配列になります。チェックボックスのグループや `<select multiple>` には `[]` を使うと、1 つだけ選ばれた場合でも配列として保存されます。

`fields.html`:

```html
<fieldset>
  <legend>Topics</legend>
  <label><input type="checkbox" name="topics[]" value="billing" /> Billing</label>
  <label><input type="checkbox" name="topics[]" value="api" /> API</label>
</fieldset>

<select name="plan">
  <option value="starter">Starter</option>
  <option value="team">Team</option>
</select>

<label><input type="checkbox" name="newsletter" /> Send me product news</label>
```

両方のトピックとニュースレターのボックスにチェックを入れると、次のように保存されます:

`保存されるフィールド`:

```json
{
  "topics": ["billing", "api"],
  "plan": "team",
  "newsletter": "on"
}
```

- `address[city]` のような角かっこを含む名前は、そのまま保存されます。ネストしたオブジェクトには変換されません。ネストした値が必要な場合は JSON を送信してください。
- チェックされていないチェックボックスは送信されません。`checkbox` の[フィールド](https://ikiform.com/ja/docs/fields.md#types)を定義すると、送られなかったボックスは `false`、チェックされたボックスは `true` として保存されます。
- 1 件の送信には最大 100 個のフィールド、128 文字までの名前、16 KB までの値を含められます。[制限](https://ikiform.com/ja/docs/limits.md)を参照してください。

> ファイルのアップロードはまだ実装されていません。空のファイル入力は無視され、実際のファイルを含む送信は `422 files_not_supported` で拒否されます。

## 予約済みフィールド

`_` で始まる名前は Ikiform への指示です。回答として保存されることはありません。

| フィールド | 効果 |
| --- | --- |
| `_gotcha` | ハニーポット。空のまま非表示にしておきます。値が入っているとスパムスコアに 5 が加算され、それだけで送信はスパムとして保存されます。名前はフォームごとに変更できます。 |
| `_redirect`, `_next` | 送信が成功したあとのブラウザーの移動先。[_redirect のルール](#redirect-rules)を参照してください。 |
| `_subject` | 通知メールの件名。空白はまとめられ、200 文字で切り詰められます。 |
| `_replyto` | 通知メールの返信先アドレス。有効なメールアドレス 1 つでない場合は無視されます。 |
| `_idempotency` | 冪等キー。`Idempotency-Key` ヘッダーと同じです。[冪等性](https://ikiform.com/ja/docs/frameworks.md#idempotency)を参照してください。 |
| `_ikiform_ts` | 署名付きの描画時刻。SDK と shadcn/ui コンポーネントが設定します。描画から 2 秒未満で送られた送信はスパムと判定されます。 |
| `cf-turnstile-response` | Turnstile のトークン。Turnstile ウィジェットまたは SDK が追加します。 |
| `_ikiform_via` | Ikiform 自身の人間確認ページが設定します。自分で送らないでください。 |

`_` で始まるその他のフィールドも除外されるので、`_source` のような名前を、保存せずに使う独自の非表示マーカーとして使えます。

`demo.html`:

```html
<form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
  <input name="email" type="email" required />
  <input type="hidden" name="_subject" value="New demo request" />
  <input type="hidden" name="_redirect" value="https://example.com/thanks" />
  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
  <button>Request a demo</button>
</form>
```

## ハニーポット

ハニーポットのデフォルト名は `_gotcha` です。フォームの設定の **Honeypot field**（ハニーポットフィールド）でフォームごとに変更でき、どの名前を選んでも予約済みとして扱われ、保存されることはありません。ほとんどのボットには `hidden` 属性だけで十分です。スパムがすり抜ける場合は、`hidden` が付いた入力欄を飛ばすボットもいるため、代わりに入力欄を画面外に隠してください:

`honeypot.html`:

```html
<div aria-hidden="true" style="position:absolute;left:-10000px;width:1px;height:1px;overflow:hidden">
  <label>
    Leave this empty
    <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" />
  </label>
</div>
```

キーボードのユーザーやパスワードマネージャーが入力しないよう、`tabindex="-1"` と `autocomplete="off"` は残してください。

## 人間確認を追加する

スパムチェックが **Ikiform** に設定されたフォームでは、HTML を変更する必要はありません。ブラウザーがトークンなしで送信すると、Ikiform は ikiform.com 上の短い「人間であることを確認しています」ページで応答します。このページが Cloudflare Turnstile を実行し、元のフィールドをトークン付きで再送信します。訪問者は以前と同じサンクスページにたどり着きます。全体の流れは[スパム対策](https://ikiform.com/ja/docs/spam.md#human-check)を参照してください。

### 独自の Turnstile キーを使う場合

フォームで **Your own Turnstile keys**（独自の Turnstile キー）を使う場合は、ウィジェットを自分で描画します。ウィジェットが送信に `cf-turnstile-response` フィールドを追加します。有効なトークンのない送信は `403 captcha_failed` で拒否されます。

`turnstile.html`:

```html
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>

<form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
  <input name="email" type="email" required />
  <div class="cf-turnstile" data-sitekey="YOUR_SITE_KEY"></div>
  <button>Send</button>
</form>
```
