# shadcn/ui コンポーネント

> 自分の shadcn/ui コンポーネントで Ikiform のフィールドを描画する、フォームコンポーネントをインストールします。

プロジェクトで shadcn/ui を使っているなら、マークアップを書く代わりに、できあがったフォームをインストールできます。これはいくつかある方法の 1 つで、同じフォームは [プレーンな HTML](https://ikiform.com/ja/docs/html.md) や [fetch](https://ikiform.com/ja/docs/frameworks.md) でも引き続き動きます。

## インストール

`ターミナル`:

```bash
npx shadcn@latest add https://ikiform.com/r/form.json
```

`components/ikiform/form.tsx` がプロジェクトにコピーされ、使用する shadcn/ui コンポーネント（`button`、`checkbox`、`input`、`label`、`radio-group`、`textarea`）がインストールされます。ファイルは自由に編集できます。セレクトはネイティブの `<select>` を使うので、shadcn/ui の Radix 版でも Base UI 版でも動きます。

## 使い方

`app/contact/page.tsx`:

```tsx
import { IkiForm } from "@/components/ikiform/form";

export default function Contact() {
  return <IkiForm form="frm_xxxxxxxxxxxxxxxx" />;
}
```

マウント時に、コンポーネントはフォームの公開スキーマを取得し、ダッシュボードで設定したラベル、プレースホルダー、ヘルプテキスト、選択肢を使って、フィールドごとにコントロールを 1 つ描画します。先にフォームの[フィールド](https://ikiform.com/ja/docs/fields.md)タブでフィールドを定義してください。フィールドのないフォームでは入力欄は描画されません。

- サーバーと同じルールとメッセージで、ブラウザーでバリデーションします。
- ハニーポットと署名付きの描画タイムスタンプを付けて JSON を送信するので、スパムの判定に役立ちます。
- サーバーからのフィールドエラーは各フィールドの下に、その他のエラーはボタンの上に表示されます。
- 成功すると、フォームをフォームの完了メッセージに置き換えます。

## Props

| プロパティ | 型 | 説明 |
| --- | --- | --- |
| `form` | `string` | 必須。フォーム ID。 |
| `fields` | `IkiFormField[]` | 取得したフィールドを置き換えます。フィールド定義と同じ形式です。 |
| `onSuccess` | `({ id, values }) => void` | 送信が成功したあとに呼ばれます。 |
| `submitLabel` | `string` | ボタンのテキスト。デフォルトはフォームの送信ボタンのラベル。 |
| `successMessage` | `ReactNode` | 送信後に表示されます。デフォルトはフォームの完了メッセージ。 |
| `turnstileSiteKey` | `string` | 独自の Turnstile キーを使い、Ikiform にサイトキーを保存していないフォームでのみ使います。 |
| `className` | `string` | フォーム要素のクラス名。 |
| `baseUrl` | `string` | デフォルトは `https://ikiform.com`。 |

`app/waitlist/page.tsx`:

```tsx
import { IkiForm } from "@/components/ikiform/form";

export default function Waitlist() {
  return (
    <IkiForm
      form="frm_xxxxxxxxxxxxxxxx"
      submitLabel="Join the waitlist"
      successMessage="You're on the list."
      onSuccess={({ id }) => console.log("Submitted", id)}
    />
  );
}
```

### コードでフィールドを定義する

`fields` を渡すと、ダッシュボードの定義を使わずに描画します。サーバーはあくまでフォームの公開済みフィールドに対してバリデーションするので、両者を同期させておいてください。

`コードでフィールドを定義する`:

```tsx
<IkiForm
  form="frm_xxxxxxxxxxxxxxxx"
  fields={[
    { id: "email", type: "email", label: "Work email", required: true },
    { id: "team_size", type: "number", label: "Team size", validation: { min: 1, integer: true } },
  ]}
/>
```

## 人間確認

スパムチェックが **Ikiform** の場合、コンポーネントは小さな ikiform.com のフレームを埋め込みます。このフレームは Turnstile がクリックを必要とするまで非表示のままで、試行のたびに新しいトークンを取得します。フレームを読み込めない場合は、新しいウィンドウで確認を開くよう案内します。独自の Turnstile キーを使う場合は、フォームのサイトキーで Turnstile ウィジェットを描画します。

## スキーマのエンドポイント

コンポーネントは `GET https://ikiform.com/f/<formId>/schema` を読み込みます。自分で呼び出して独自のレンダラーを作ることも、[SDK](https://ikiform.com/ja/docs/sdk.md#getschema) の `getSchema` を使うこともできます。

`GET /f/:formId/schema`:

```json
{
  "id": "frm_xxxxxxxxxxxxxxxx",
  "title": "Contact",
  "description": null,
  "fields": [{ "id": "email", "type": "email", "label": "Email", "required": true }],
  "settings": { "submit_label": "Send", "success_message": "Thanks!" },
  "honeypot_field": "_gotcha",
  "turnstile_required": false,
  "turnstile_site_key": null,
  "challenge": null,
  "ts": "1792300000000.signature"
}
```

- どのオリジンからも利用でき（`Access-Control-Allow-Origin: *`）、キャッシュされません。
- 一時停止中、無効、存在しないフォームは、いずれも同じ `404` を返します。
- サーバーの外に出るのは、公開済みのフィールドと表示設定だけです。許可ドメイン、リダイレクト URL、スパムの設定、レート制限は非公開のままです。
- `challenge` は `{ "provider": "ikiform", "url": ... }`、`{ "provider": "custom", "site_key": ... }`、`null` のいずれかです。`ts` は新しい署名付きの描画タイムスタンプで、`_ikiform_ts` として送り返します。
- 訪問者とフォームごとに 1 分あたり 60 リクエストまで使え、送信の許容量とは別に数えます。

> コンポーネントのソースは素の React と Tailwind です。読むのも、スタイルを変えるのも、不要な部分を削除するのも自由です。
