Next.js
Sende aus einer Client-Komponente im Next.js App Router oder über eine Server Action mit einem Secret Key.
Es gibt zwei gute Wege, aus Next.js zu senden. Sende aus dem Browser in einer Client-Komponente, was die eigene IP jedes Besuchers für Rate-Limits beibehält und mit jeder Spamprüfung funktioniert. Oder sende aus einer Server Action, was das Formular auch ohne JavaScript funktionieren lässt.
| Item | Client-Komponente | Server Action |
|---|---|---|
| Funktioniert ohne JavaScript | Nein | Ja |
| Rate-Limits zählen | Jeden Besucher | Die IP deines Servers |
| Ikiform-Menschlichkeitsprüfung | Verwende challenge aus dem SDK | Mit einem Secret Key übersprungen |
| Erlaubte Domains | Gegen den Origin des Browsers geprüft | Mit einem Secret Key übersprungen |
| Braucht einen Secret Key | Nein | Ja |
SDK installieren
npm install @ikiform/sdkDas SDK ist optional. Alles Folgende funktioniert auch mit fetch; siehe JavaScript und fetch.
Aus einer Client-Komponente
"use client";
import { submit } from "@ikiform/sdk";
import { useState } from "react";
type Status = "idle" | "sending" | "sent" | "error";
export function ContactForm() {
const [status, setStatus] = useState<Status>("idle");
const [errors, setErrors] = useState<Record<string, string[]>>({});
const [message, setMessage] = useState("");
async function onSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault();
setStatus("sending");
const result = await submit("frm_xxxxxxxxxxxxxxxx", new FormData(event.currentTarget));
if (result.ok) return setStatus("sent");
setErrors(result.error.fields ?? {});
setMessage(result.error.message);
setStatus("error");
}
if (status === "sent") return <p>Thanks, we got it.</p>;
return (
<form onSubmit={onSubmit} noValidate>
<label htmlFor="email">Email</label>
<input id="email" name="email" type="email" required aria-invalid={Boolean(errors.email)} />
{errors.email ? <p>{errors.email[0]}</p> : null}
<label htmlFor="message">Message</label>
<textarea id="message" name="message" />
<input name="_gotcha" type="text" tabIndex={-1} autoComplete="off" hidden />
{status === "error" && !Object.keys(errors).length ? <p role="alert">{message}</p> : null}
<button disabled={status === "sending"}>{status === "sending" ? "Sending" : "Send"}</button>
</form>
);
}submitwirft nie. Es liefert{ ok: true, id }oder{ ok: false, error, status, requestId }.error.fieldsordnet Feld-IDs Meldungen zu, wenn das Formular definierte Felder hat.- Rendere die Komponente aus einer beliebigen Server-Komponenten-Seite, zum Beispiel
app/contact/page.tsx.
Mit der Ikiform-Menschlichkeitsprüfung
Ist die Spamprüfung des Formulars Ikiform, hol dir direkt vor jedem Absenden ein Token. challenge bindet einen kleinen ikiform.com-Frame ein, der unsichtbar bleibt, außer Turnstile braucht einen Klick.
const data = new FormData(event.currentTarget);
const turnstileToken = await challenge("frm_xxxxxxxxxxxxxxxx");
const result = await submit("frm_xxxxxxxxxxxxxxxx", data, { turnstileToken });Importiere es mit import { challenge, submit } from "@ikiform/sdk";. Tokens sind nur einmal gültig, also ruf es einmal pro Absenden auf.
Aus einer Server Action
Erstelle im Dashboard unter API keys einen Secret Key mit dem Scope submissions:write und speichere ihn als Umgebungsvariable. Gib ihn nie an den Browser weiter: Versieh ihn nicht mit dem Präfix NEXT_PUBLIC_.
IKIFORM_SECRET_KEY=ik_sk_your_secret_key"use server";
export interface ContactState {
ok: boolean;
message: string;
fields?: Record<string, string[]>;
}
export async function sendContact(_previous: ContactState, formData: FormData): Promise<ContactState> {
const body = new URLSearchParams();
for (const [name, value] of formData) {
if (typeof value === "string" && !name.startsWith("$ACTION")) body.append(name, value);
}
const response = await fetch("https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx", {
method: "POST",
headers: {
Accept: "application/json",
Authorization: `Bearer ${process.env.IKIFORM_SECRET_KEY}`,
},
body,
});
const result = await response.json();
if (result.ok) return { ok: true, message: "Thanks, we got it." };
return { ok: false, message: result.error.message, fields: result.error.fields };
}"use client";
import { useActionState } from "react";
import { type ContactState, sendContact } from "./actions";
const initial: ContactState = { ok: false, message: "" };
export function ContactForm() {
const [state, action, pending] = useActionState(sendContact, initial);
if (state.ok) return <p>{state.message}</p>;
return (
<form action={action}>
<label htmlFor="email">Email</label>
<input id="email" name="email" type="email" required />
{state.fields?.email ? <p>{state.fields.email[0]}</p> : null}
<label htmlFor="message">Message</label>
<textarea id="message" name="message" />
{state.message && !state.fields ? <p role="alert">{state.message}</p> : null}
<button disabled={pending}>{pending ? "Sending" : "Send"}</button>
</form>
);
}Das submit des SDK lässt sich auch in einer Server Action verwenden, sendet aber keinen Authorization-Header, sodass ein Formular mit erlaubten Domains oder der Ikiform-Menschlichkeitsprüfung den Post ablehnen oder markieren würde. Verwende fetch mit dem Secret Key wie gezeigt.
Webhooks in einem Route Handler empfangen
Um in deiner Next.js-App auf jede Einsendung zu reagieren, füge einen Route Handler hinzu. Siehe Webhooks empfangen.