# SvelteKit

> Uma página SvelteKit pré-renderizada cujo formulário envia direto para o Ikiform, aprimorada com fetch quando o JavaScript carrega. Funciona com adapter-static.

Esta página não precisa de servidor: o `action` do formulário é o seu endpoint do Ikiform, então funciona com `adapter-static` e em qualquer host estático. Sem JavaScript, ela envia e redireciona como HTML puro; com JavaScript, envia com `fetch` e mostra o resultado no lugar. Para enviar por uma form action com uma chave secreta, veja [Svelte](https://ikiform.com/pt-br/docs/guides/svelte.md#sveltekit).

## Por que não usar use:enhance

O `use:enhance` do SvelteKit só funciona com formulários `method="POST"` que apontam para actions definidas em um arquivo `+page.server.js`. O Ikiform é uma URL externa, então a página usa um pequeno handler `onsubmit`. O progressive enhancement é o mesmo: o formulário funciona primeiro, e o script o melhora.

## Configuração

### Passo 1: Adicione variáveis de ambiente públicas

`.env`:

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

`PUBLIC_SITE_URL` serve para o redirecionamento sem JavaScript. Durante a pré-renderização, `page.url.origin` é `http://sveltekit-prerender`, não o seu domínio, então o redirecionamento não pode ser montado a partir dele.

### Passo 2: Pré-renderize a página

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

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

### Passo 3: Adicione o formulário

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

Adicione um `src/routes/contact/thanks/+page.svelte` como destino do redirecionamento.

## Se você usa a CSP do SvelteKit

Com `kit.csp` configurado, permita o Ikiform tanto para o envio com `fetch` quanto para o envio do formulário comum. Caso contrário, o navegador bloqueia um ou outro.

`svelte.config.js`:

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

export default config;
```

## Domínios permitidos

Liste a produção mais os seus hosts de preview.

| Onde o formulário roda | Adicione em Allowed domains |
| --- | --- |
| `vite dev` | `localhost`. Ele corresponde a `http://localhost:5173`: o Ikiform compara só o nome do host, nunca a porta. |
| Seu domínio | `example.com`, que também cobre `www.example.com` |
| Vercel | `your-project.vercel.app`. URLs de preview como `your-project-git-branch-team.vercel.app` não correspondem a ele; adicione o host exato do preview enquanto testa um. |
| Cloudflare Pages | `your-project.pages.dev`. URLs de preview como `abc123.your-project.pages.dev` são subdomínios dele, então já correspondem. |
| Netlify | `your-site.netlify.app`. Deploy previews (`deploy-preview-12--your-site.netlify.app`) e branch deploys (`branch--your-site.netlify.app`) não são subdomínios dele, então adicione o host exato do preview enquanto testa um. |

- Nunca adicione `vercel.app`, `pages.dev` ou `netlify.app` sozinhos. Todo site naquele host corresponderia, inclusive os de outras pessoas.

## Checklist de teste

1. Rode o servidor de desenvolvimento com `localhost` nos domínios permitidos e envie. A mensagem de agradecimento deve substituir o formulário.
2. Rode `vite build` e confira se o resultado contém `contact.html` com o formulário já dentro.
3. Desative o JavaScript, recarregue e envie. No seu domínio `https:`, você deve chegar a `/contact/thanks`.
4. Envie a partir de um deploy de preview e confirme que ele não é marcado como spam.

## Solução de problemas

| O que você vê | Por quê | Correção |
| --- | --- | --- |
| O build falha dizendo que `PUBLIC_IKIFORM_FORM_ID` não é exportado por `$env/static/public` | A variável não está definida onde o build roda | Adicione em `.env` localmente e nas configurações de build do seu host. |
| Nada acontece ao enviar, e o console mostra um erro de CORS sobre o header `x-sveltekit-action` | `use:enhance` em um formulário que envia para fora do seu app | Remova-o e mantenha o handler `onsubmit`. |
| O navegador se recusa a enviar o formulário por causa de `form-action` ou `connect-src` | `kit.csp` não inclui o Ikiform | Adicione `https://ikiform.com` às duas diretivas. |
| Sem JavaScript, você cai na página de agradecimento do Ikiform | `PUBLIC_SITE_URL` é `http:`, ou o domínio não está nos domínios permitidos | Use o seu endereço `https:` e adicione o domínio. |
| Os envios chegam no filtro de spam com `origin_mismatch` | A página que enviou não está nos domínios permitidos do formulário | Adicione o host da tabela acima. Com **Reject** escolhido, os mesmos envios recebem `403 origin_not_allowed`. |

## Relacionados

- [Svelte](https://ikiform.com/pt-br/docs/guides/svelte.md): Um componente Svelte 5 e uma server action.
- [Astro](https://ikiform.com/pt-br/docs/guides/astro.md): Um formulário sem JavaScript, com melhoria opcional.
- [Domínios permitidos](https://ikiform.com/pt-br/docs/spam.md#allowed-domains): Como as origens são comparadas e o que acontece quando não correspondem.
- [Erros](https://ikiform.com/pt-br/docs/errors.md): Todos os códigos de erro, com causa e correção.
