Formular-ID

SvelteKit

Eine vorgerenderte SvelteKit-Seite, deren Formular direkt an Ikiform sendet und mit fetch erweitert wird, sobald JavaScript lädt. Funktioniert mit adapter-static.

Diese Seite braucht keinen Server: Die action des Formulars ist dein Ikiform-Endpunkt, daher funktioniert sie mit adapter-static und auf jedem statischen Host. Ohne JavaScript sendet sie und leitet weiter wie einfaches HTML; mit JavaScript sendet sie per fetch und zeigt das Ergebnis direkt an. Um stattdessen über eine Form Action mit einem geheimen Schlüssel zu senden, siehe Svelte.

Warum nicht use:enhance

use:enhance von SvelteKit funktioniert nur mit method="POST"-Formularen, die auf Actions in einer +page.server.js-Datei zeigen. Ikiform ist eine externe URL, daher nutzt die Seite stattdessen einen kleinen onsubmit-Handler. Die Progressive Enhancement ist dieselbe: Das Formular funktioniert zuerst, das Skript verbessert es.

Einrichten

  1. Füge öffentliche Umgebungsvariablen hinzu

    .env
    PUBLIC_IKIFORM_FORM_ID=frm_xxxxxxxxxxxxxxxx
    PUBLIC_SITE_URL=https://example.com

    PUBLIC_SITE_URL ist für die Weiterleitung ohne JavaScript. Beim Prerendering ist page.url.origin http://sveltekit-prerender, nicht deine Domain, daher lässt sich die Weiterleitung nicht daraus bauen.

  2. Prerendere die Seite

    src/routes/contact/+page.js
    export const prerender = true;
  3. Füge das Formular hinzu

    src/routes/contact/+page.svelte
    <script>
      import { PUBLIC_IKIFORM_FORM_ID, PUBLIC_SITE_URL } from "$env/static/public";
    
      const endpoint = `https://ikiform.com/f/${PUBLIC_IKIFORM_FORM_ID}`;
    
      let status = $state("idle");
      let errors = $state({});
      let message = $state("");
    
      async function onsubmit(event) {
        event.preventDefault();
        status = "sending";
        try {
          const response = await fetch(endpoint, {
            method: "POST",
            headers: { Accept: "application/json" },
            body: new FormData(event.currentTarget),
          });
          const result = await response.json();
          if (result.ok) {
            status = "sent";
            return;
          }
          errors = result.error.fields ?? {};
          message = result.error.message;
        } catch {
          message = "Couldn't reach the server. Try again.";
        }
        status = "error";
      }
    </script>
    
    {#if status === "sent"}
      <p>Thanks, we got it.</p>
    {:else}
      <form action={endpoint} method="POST" {onsubmit}>
        <label>
          Email
          <input name="email" type="email" autocomplete="email" required aria-invalid={errors.email ? "true" : undefined} />
        </label>
        {#if errors.email}<p>{errors.email[0]}</p>{/if}
        <label>
          Message
          <textarea name="message" rows="5"></textarea>
        </label>
        <input type="hidden" name="_redirect" value={`${PUBLIC_SITE_URL}/contact/thanks`} />
        <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
        {#if status === "error" && !errors.email}<p role="alert">{message}</p>{/if}
        <button disabled={status === "sending"}>{status === "sending" ? "Sending" : "Send"}</button>
      </form>
    {/if}

    Füge eine src/routes/contact/thanks/+page.svelte als Weiterleitungsziel hinzu.

Wenn du die CSP von SvelteKit nutzt

Wenn kit.csp konfiguriert ist, erlaube Ikiform sowohl für den fetch-Post als auch für den einfachen Formular-Post. Sonst blockiert der Browser das eine oder das andere.

svelte.config.js
const config = {
  kit: {
    csp: {
      directives: {
        "connect-src": ["self", "https://ikiform.com"],
        "form-action": ["self", "https://ikiform.com"],
      },
    },
  },
};

export default config;

Erlaubte Domains

Liste die Produktion plus deine Preview-Hosts auf.

Wo das Formular läuftZu Allowed domains hinzufügen
vite devlocalhost. Passt auf http://localhost:5173: Ikiform vergleicht nur den Hostnamen, nie den Port.
Deine Domainexample.com, was auch www.example.com abdeckt
Vercelyour-project.vercel.app. Preview-URLs wie your-project-git-branch-team.vercel.app passen nicht darauf; füge den exakten Preview-Host hinzu, während du eine Preview testest.
Cloudflare Pagesyour-project.pages.dev. Preview-URLs wie abc123.your-project.pages.dev sind Subdomains davon und passen daher bereits.
Netlifyyour-site.netlify.app. Deploy Previews (deploy-preview-12--your-site.netlify.app) und Branch Deploys (branch--your-site.netlify.app) sind keine Subdomains davon, füge also den exakten Preview-Host hinzu, während du eine testest.
  • Füge niemals vercel.app, pages.dev oder netlify.app allein hinzu. Jede Site auf diesem Host würde passen, auch die von anderen Leuten.

Test-Checkliste

  1. Starte den Dev-Server mit localhost in den erlaubten Domains und sende ab. Die Dankesnachricht sollte das Formular ersetzen.
  2. Starte vite build und prüfe, dass die Ausgabe contact.html mit dem Formular darin enthält.
  3. Schalte JavaScript aus, lade neu und sende ab. Auf deiner https:-Domain solltest du auf /contact/thanks landen.
  4. Sende von einem Preview-Deploy ab und prüfe, dass die Einsendung nicht als Spam markiert ist.

Fehlerbehebung

Was du siehstWarumLösung
Der Build schlägt fehl mit der Meldung, dass PUBLIC_IKIFORM_FORM_ID nicht von $env/static/public exportiert wirdDie Variable ist dort, wo der Build läuft, nicht gesetztFüge sie lokal zu .env und zu den Build-Einstellungen deines Hosts hinzu.
Beim Absenden passiert nichts, und die Konsole zeigt einen CORS-Fehler zum x-sveltekit-action-Headeruse:enhance auf einem Formular, das außerhalb deiner App sendetEntferne es und behalte den onsubmit-Handler.
Der Browser verweigert das Senden des Formulars wegen form-action oder connect-srckit.csp listet Ikiform nicht aufFüge https://ikiform.com zu beiden Direktiven hinzu.
Ohne JavaScript landest du auf der Dankesseite von IkiformPUBLIC_SITE_URL ist http:, oder die Domain steht nicht in den erlaubten DomainsVerwende deine https:-Adresse und füge die Domain hinzu.
Einsendungen landen im Spamfilter mit origin_mismatchDie sendende Seite steht nicht in den erlaubten Domains des FormularsFüge den Host aus der Tabelle oben hinzu. Mit Reject bekommen dieselben Requests stattdessen 403 origin_not_allowed.