send.webforms.toRead the docs →

Frameworks and libraries

Add a contact form to Alpine.js

Alpine exists for exactly this situation: you want a bit of interactivity on an otherwise static page, and you do not want a build pipeline to get it. A whole contact form (loading state, success message, error handling) fits in one x-data object and a script tag. No bundler, no framework, no backend.

Get an endpointRead the docs

Setup

  1. Copy your endpoint

    Create a form in the dashboard.

  2. Add Alpine and the form

    One CDN script tag plus the markup below. Nothing to compile.

Alpine.js examples

Swap in your own endpoint and these run as-is.

index.html
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3/dist/cdn.min.js"></script>

<div
  x-data="{
    status: 'idle',
    error: null,
    async submit(e) {
      this.status = 'sending';
      this.error = null;

      const res = await fetch('https://send.webforms.to/wft_your_key', {
        method: 'POST',
        headers: { accept: 'application/json' },
        body: new FormData(e.target),
      });

      const data = await res.json();

      if (data.ok) {
        this.status = 'sent';
        e.target.reset();
      } else {
        this.error = data.message;
        this.status = 'error';
      }
    }
  }"
>
  <p x-show="status === 'sent'" role="status">Thanks, we got it.</p>

  <form x-show="status !== 'sent'" @submit.prevent="submit">
    <input name="name" placeholder="Your name" required />
    <input name="email" type="email" placeholder="you@example.com" required />
    <textarea name="message" placeholder="Message" required></textarea>

    <input name="_gotcha" tabindex="-1" aria-hidden="true"
           style="position:absolute;left:-9999px" />

    <button :disabled="status === 'sending'"
            x-text="status === 'sending' ? 'Sending…' : 'Send'"></button>

    <p x-show="error" x-text="error" role="alert"></p>
  </form>
</div>

Alpine.js form FAQ

Keep a small x-data state with sending, sent and error, submit with fetch and Accept: application/json, and toggle the message with x-show. That is the whole reason to add Alpine here. The form works without it.

Where Alpine.js submissions can go

The guide above gets the submission to your endpoint. From there it can land anywhere: one destination on Free, several on Pro.

Need the form markup too? The template gallery has complete forms for contact, waitlist, job application and more, and the form generator builds one field by field.

Ready to wire up your Alpine.js form?

Free for 300 submissions a month. Endpoint in under a minute, no card required.

Start free