Blog

Astro Contact Form — Zero JS Required

Add a working contact form to an Astro site with a plain .astro component and no client-side JavaScript — just point the form at a FormBridge endpoint.

← Back to the blog
AI Powered

Explore this article with AI

Get an instant summary, key takeaways, action items, and answers to your questions about this article.

Choose your AI assistant
ChatGPT Perplexity
Quick answer

Add a plain <form> to any Astro component or page and set its action to your FormBridge endpoint URL — Astro ships zero JavaScript by default, so no client directive or hydration is needed for the form to submit and trigger an email notification.

Why Astro doesn't need a form library

Astro ships zero JavaScript to the client by default — that's the whole pitch of the framework. A <form> element doesn't need a client directive, a signal, or an island to submit; the browser already knows how to POST a form to a URL. The only decision you're making is what URL to point it at.

For a contact form, that URL can be a FormBridge endpoint instead of a route you'd have to build and maintain yourself.

The component

---
// src/components/ContactForm.astro
---
<form action="https://app.formbridge.ai/api/forms/fb_8h2k9p" method="POST" class="contact-form">
  <label for="full-name">Full name</label>
  <input id="full-name" name="full-name" type="text" required />

  <label for="email">Email</label>
  <input id="email" name="email" type="email" required />

  <label for="message">Message</label>
  <textarea id="message" name="message" rows="5" required></textarea>

  <button type="submit">Send message</button>
</form>

<style>
  .contact-form {
    display: grid;
    gap: 0.75rem;
    max-width: 480px;
  }
</style>

Drop that into any .astro page or layout and it's done — no client:load, no useState, no hydration budget spent on a form that doesn't need any interactivity.

What actually happens on submit

The browser does a normal full-page POST. FormBridge receives it, runs it through spam scoring, and — assuming it passes — emails your recipient list and, if configured, sends an autoresponder back to whoever filled it in. The response is JSON ({ "ok": true, "id": "sub_..." }), so without any JavaScript the visitor's browser will navigate to that raw JSON after submitting.

For an internal tool that's often fine as-is. For a public site, most teams eventually add a few lines of fetch() in a <script> tag to intercept the submit and swap in a "thanks, we got it" message instead — but that's a UX polish step, not a requirement. The form works, and the email arrives, with zero JS shipped.

Spam protection without extra Astro code

Nothing here changes for spam protection — it's configured on the FormBridge side, per form, not in your Astro code. Turn on a honeypot field or CAPTCHA from the form's Settings → Spam Protection tab and every submission through this same endpoint gets the extra layer, with no component changes required.

Frequently asked

Do I need a client:load directive on an Astro contact form?

No. A plain HTML form only needs JavaScript for behaviors like intercepting submit or showing inline validation; submitting to an external endpoint like FormBridge works fine with a static, non-hydrated form.

What happens after someone submits an Astro form with no JavaScript?

The browser does a full-page POST and navigates to whatever the endpoint returns. FormBridge returns a small JSON response, so without JS the visitor will briefly see that JSON page after submitting.

Can I still add spam protection to a zero-JS Astro form?

Yes — CAPTCHA, honeypot fields, and domain allow-lists are configured on the form backend side (in FormBridge's Settings → Spam Protection), not in the Astro component, so none of it requires client-side code.

Key facts

  • Astro renders components to static HTML by default and only ships JavaScript for parts explicitly marked with a client directive.
  • A plain HTML <form> submits with the browser's native POST behavior and needs no JavaScript framework to function.
  • FormBridge's endpoint returns a JSON response ({ ok: true, id: ... }) on a successful submission, which a script-free form will display as a raw page after redirecting.

Terms in this post

Client directive
An Astro-specific attribute (e.g. client:load, client:visible) that opts a specific component into shipping JavaScript and hydrating in the browser; components without one render as static HTML only.

Get the next one in your inbox.

One email when we publish something worth reading. No spam — appropriately enough, we'd know.