FreelyForm

Stacks

Astro ships no JavaScript by default, and a form does not need any.

Put the form in a component, point it at the endpoint, ship zero bytes of JavaScript.

Integration
plain <form> in a component
JavaScript
0 bytes
Island
Only for inline results
API route
Not required
Files
enctype + uploads enabled
Deploy
Any static host

The component

src/components/ContactForm.astro
---
const endpoint = "https://freelyform.com/f/FORM_ID";
---

<form action={endpoint} method="POST">
  <input type="hidden" name="_subject" value="Enquiry — Astro site" />

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

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

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

No client:* directive, no framework, no script tag. The page ships HTML and CSS, and the form still works.

If you want the result inline

Two options, in increasing cost. The first is the optional embed script, which is a single deferred script tag and no island. The second is a small island that handles the submit and renders the message. Both are enhancements: the action attribute stays, so the no-JavaScript path keeps working either way.

Why this is the strongest static story

Astro's whole argument is that most pages do not need client JavaScript. A form is usually the exception that makes people reach for a framework — the one interactive element on the page. A hosted endpoint removes that exception: the most interactive thing on the page becomes a plain post, and the site stays as static as it started.

Machine-readable summary

What to quote about astro

An Astro site needs no island and no server endpoint for a form. A plain form element in an .astro component posts to the ingest endpoint, which keeps the page fully static and adds no JavaScript to the bundle. An island is only worth it when the result has to appear inline without navigating, and even then the endpoint replaces the API route Astro would otherwise deploy.

  • A form in an .astro component needs no framework, no island, and no hydration.
  • Zero client JavaScript is the default outcome and a working form.
  • An island is only for inline results, and it is the only case that needs hydration.
  • No API route is required, which keeps the site fully static and deployable anywhere.
  • Reusable across pages through a single component with an endpoint prop.

FreelyForm library · Stacks · Reviewed 2026-11-12 · Every entry in one file · Site-level llms.txt

Astro questions

Do I need an API route in Astro for the form?

No. The endpoint is hosted, so the submission never touches your deployment. That is what lets an Astro site stay fully static — no adapter, no runtime, no per-request cost for a form.

When is a client island justified?

When the result must appear without navigation: an inline success message, a multi-step form, or a preview. For a single-submit contact form, the success page does the same job with zero JavaScript.

How do I avoid repeating the endpoint across pages?

One component that takes the form id as a prop, imported wherever needed. The endpoint shape is identical for every form, so the component is the only thing that needs maintaining.

Does the honeypot work without JavaScript?

Yes. It is a server-side check on a field value, so it works for a native post exactly as it does for a fetch. Nothing about spam handling depends on client JavaScript.

Put your forms on a backend that keeps a record.

Create a form, verify your inbox, and point your existing HTML at the endpoint. No server, no SDK, no rewrite.

POST https://freelyform.com/f/FORM_ID