# SvelteKit

> Une page SvelteKit prérendue dont le formulaire envoie directement à Ikiform, améliorée avec fetch une fois JavaScript chargé. Compatible avec adapter-static.

Cette page n'a pas besoin de serveur : l'`action` du formulaire est votre endpoint Ikiform, donc elle fonctionne avec `adapter-static` et n'importe quel hébergeur statique. Sans JavaScript, elle envoie et redirige comme du HTML classique ; avec JavaScript, elle envoie avec `fetch` et affiche le résultat sur place. Pour envoyer plutôt via une form action avec une clé secrète, voir [Svelte](https://ikiform.com/fr/docs/guides/svelte.md#sveltekit).

## Pourquoi pas use:enhance

Le `use:enhance` de SvelteKit ne fonctionne qu'avec des formulaires `method="POST"` qui pointent vers des actions définies dans un fichier `+page.server.js`. Ikiform est une URL externe, donc la page utilise à la place un petit handler `onsubmit`. L'amélioration progressive est la même : le formulaire fonctionne d'abord, le script l'améliore ensuite.

## Mise en place

### Étape 1 : Ajoutez des variables d'environnement publiques

`.env`:

```bash
PUBLIC_IKIFORM_FORM_ID=frm_xxxxxxxxxxxxxxxx
PUBLIC_SITE_URL=https://example.com
```

`PUBLIC_SITE_URL` sert à la redirection sans JavaScript. Pendant le prérendu, `page.url.origin` vaut `http://sveltekit-prerender` et non votre domaine, donc la redirection ne peut pas être construite à partir de lui.

### Étape 2 : Prérendez la page

`src/routes/contact/+page.js`:

```js
export const prerender = true;
```

### Étape 3 : Ajoutez le formulaire

`src/routes/contact/+page.svelte`:

```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}
```

Ajoutez un `src/routes/contact/thanks/+page.svelte` comme cible de redirection.

## Si vous utilisez la CSP de SvelteKit

Avec `kit.csp` configuré, autorisez Ikiform à la fois pour l'envoi `fetch` et pour l'envoi de formulaire classique. Sinon, le navigateur bloque l'un ou l'autre.

`svelte.config.js`:

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

export default config;
```

## Domaines autorisés

Listez la production ainsi que vos hôtes de prévisualisation.

| Où tourne le formulaire | À ajouter aux domaines autorisés |
| --- | --- |
| `vite dev` | `localhost`. Correspond à `http://localhost:5173` : Ikiform compare uniquement le nom d'hôte, jamais le port. |
| Votre domaine | `example.com`, qui couvre aussi `www.example.com` |
| Vercel | `your-project.vercel.app`. Les URL de prévisualisation comme `your-project-git-branch-team.vercel.app` ne correspondent pas ; ajoutez l'hôte de prévisualisation exact le temps de le tester. |
| Cloudflare Pages | `your-project.pages.dev`. Les URL de prévisualisation comme `abc123.your-project.pages.dev` en sont des sous-domaines, donc elles correspondent déjà. |
| Netlify | `your-site.netlify.app`. Les deploy previews (`deploy-preview-12--your-site.netlify.app`) et les branch deploys (`branch--your-site.netlify.app`) n'en sont pas des sous-domaines : ajoutez l'hôte de prévisualisation exact le temps de le tester. |

- N'ajoutez jamais `vercel.app`, `pages.dev` ou `netlify.app` seul. Tous les sites de cet hébergeur correspondraient, y compris ceux des autres.

## Checklist de test

1. Lancez le serveur de développement avec `localhost` dans les domaines autorisés et envoyez. Le message de remerciement doit remplacer le formulaire.
2. Lancez `vite build` et vérifiez que le résultat contient `contact.html` avec le formulaire déjà présent.
3. Désactivez JavaScript, rechargez et envoyez. Sur votre domaine `https:`, vous devez arriver sur `/contact/thanks`.
4. Envoyez depuis un déploiement de prévisualisation et vérifiez que l'envoi n'est pas marqué comme spam.

## Dépannage

| Ce que vous voyez | Pourquoi | Solution |
| --- | --- | --- |
| Le build échoue en indiquant que `PUBLIC_IKIFORM_FORM_ID` n'est pas exporté par `$env/static/public` | La variable n'est pas définie là où le build s'exécute | Ajoutez-la à `.env` en local et aux réglages de build de votre hébergeur. |
| Rien ne se passe à l'envoi, et la console affiche une erreur CORS à propos de l'en-tête `x-sveltekit-action` | `use:enhance` sur un formulaire qui envoie hors de votre app | Retirez-le et gardez le handler `onsubmit`. |
| Le navigateur refuse d'envoyer le formulaire à cause de `form-action` ou `connect-src` | `kit.csp` ne liste pas Ikiform | Ajoutez `https://ikiform.com` aux deux directives. |
| Sans JavaScript, vous arrivez sur la page de remerciement d'Ikiform | `PUBLIC_SITE_URL` est en `http:`, ou le domaine ne fait pas partie des domaines autorisés | Utilisez votre adresse `https:` et ajoutez le domaine. |
| Les soumissions arrivent dans le filtre spam avec `origin_mismatch` | La page qui a envoyé ne fait pas partie des domaines autorisés du formulaire | Ajoutez l'hôte du tableau ci-dessus. Avec **Reject**, les mêmes envois reçoivent plutôt `403 origin_not_allowed`. |

## Voir aussi

- [Svelte](https://ikiform.com/fr/docs/guides/svelte.md): Un composant Svelte 5 et une server action.
- [Astro](https://ikiform.com/fr/docs/guides/astro.md): Un formulaire sans JavaScript, amélioré si vous le souhaitez.
- [Domaines autorisés](https://ikiform.com/fr/docs/spam.md#allowed-domains): Comment les origines sont comparées, et ce qui se passe en cas de non-correspondance.
- [Erreurs](https://ikiform.com/fr/docs/errors.md): Chaque code d'erreur, avec sa cause et sa solution.
