# Svelte and SvelteKit forms

A copy-paste Svelte 5 form component that submits to Nisuform from Svelte or SvelteKit, without a form action or +page.server.js.

Collect the fields, `POST` them to your endpoint and check the response. In SvelteKit you don't need a form action or `+page.server.js`, because the browser posts straight to Nisuform and the form key is safe to publish.

<Callout title="Generated for your form">
  The form's **Setup** tab, under **Code**, has this component ready with your endpoint and field names filled in. **Your design** gives you the styled form from the builder as a component. **Your own styles** gives you a bare component to style your way.
</Callout>

## The component

The component uses Svelte 5 runes.

```svelte title="src/lib/ContactForm.svelte"
<script>
  const shownAt = Date.now()
  let status = $state('idle')

  async function onsubmit(event) {
    event.preventDefault()
    status = 'sending'
    const data = new FormData(event.currentTarget)
    data.set('_elapsed', String(Date.now() - shownAt))
    const response = await fetch('https://api.nisuform.com/s/YOUR_FORM_KEY', {
      method: 'POST',
      headers: { Accept: 'application/json' },
      body: data,
    })
    status = response.ok ? 'sent' : 'error'
  }
</script>

{#if status === 'sent'}
  <p>Thanks! We got your message.</p>
{:else}
  <form {onsubmit}>
    <input type="email" name="email" placeholder="Email" required />
    <textarea name="message" rows="5" required></textarea>
    <input type="text" name="_gotcha" tabindex="-1" autocomplete="off" style="display: none" />
    <button type="submit" disabled={status === 'sending'}>Send</button>
    {#if status === 'error'}
      <p role="alert">Something went wrong. Please try again.</p>
    {/if}
  </form>
{/if}
```

## Use it in SvelteKit

```svelte title="src/routes/contact/+page.svelte"
<script>
  import ContactForm from '$lib/ContactForm.svelte'
</script>

<ContactForm />
```

## What it does

* Sends `Accept: application/json`, so Nisuform answers with JSON instead of the thank-you page. See [JavaScript and fetch](/docs/connect/javascript).
* Adds `_elapsed`, the time the form was open, and keeps the hidden `_gotcha` honeypot empty. Both feed [spam protection](/docs/protection/spam). See [Special fields](/docs/connect/special-fields).
* Shows a success message when the submission is accepted, and an error when it isn't.
