Learning Astro - Forms & Interactions
Episode 10 of 24

Learning Astro - Forms & Interactions

This episode covers forms and interactions in Astro: form handling on static and server pages, client-side interactions with hydrated components, UI validation and progressive enhancement, and form submission through serverless functions or endpoints.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

A form is the bridge between visitors and site owners: newsletters, contact, signups, or search. Episode 10 covers how to build forms in Astro with the right patterns — from a simple HTML form to an interactive one that sends data to a serverless function.

The key to this chapter is progressive enhancement: a form must keep working even if JavaScript fails to load. You will learn to build forms that work in two layers — pure HTML for the base, and JavaScript interaction for a smoother experience.

This episode also covers UI validation, feedback for users, and how to connect forms to serverless endpoints.

Form Handling on Astro Pages

Pure HTML Forms That Work Without JavaScript

The most basic form needs no JavaScript at all. Use the standard HTML action and method attributes:

Form HTML statis
<form action="/api/pendaftaran" method="POST">
  <label for="email">Email</label>
  <input id="email" name="email" type="email" required />
  <button type="submit">Daftar</button>
</form>

The form above sends data with method="POST" to /api/pendaftaran. This is the foundation of progressive enhancement — even without a single line of JavaScript, the form still works.

POST Endpoints in Astro

To receive form submissions, create an endpoint in src/pages/api. In server mode, you can write a handler with the post function:

JSEndpoint API form
export async function post({ request }) {
  const formData = await request.formData();
  const email = formData.get("email");
 
  if (!email) {
    return new Response("Email wajib diisi", { status: 400 });
  }
 
  return new Response("Terima kasih sudah mendaftar", { status: 200 });
}

The endpoint above reads request.formData() from the form submission, validates the email, and returns a response. The request.formData() pattern is only available in server mode — in static mode you need a serverless function from your hosting platform.

Client-Side Interaction with Hydrated Components

Interactive Forms with Framework Components

For real-time feedback — validation while typing, loading indicators, or success messages without a reload — wrap the form in a hydrated component:

JSKomponen form dengan React
export default function FormDaftar() {
  const [status, setStatus] = useState("idle");
 
  async function kirim(event) {
    event.preventDefault();
    setStatus("loading");
    const body = new FormData(event.currentTarget);
    const res = await fetch("/api/pendaftaran", { method: "POST", body });
    setStatus(res.ok ? "sukses" : "gagal");
  }
 
  return (
    <form onSubmit={kirim}>
      <input name="email" type="email" required />
      <button type="submit" disabled={status === "loading"}>
        {status === "loading" ? "Mengirim..." : "Daftar"}
      </button>
    </form>
  );
}

This component is hydrated with client:load on the Astro page. The form uses fetch to send data without a reload, and shows a loading status while submitting.

UI Validation and Progressive Enhancement

Two-Layer Validation

Use validation in two places: HTML attributes such as required, type="email", and minlength on the browser side, then validate again on the server. HTML attributes are the first layer; server validation is the real layer — never rely only on JavaScript.

Validasi HTML bawaan
<input name="email" type="email" required minlength="5" />

The type="email" and required attributes make the browser reject empty or incorrectly formatted input before the form is sent — without a single line of JavaScript.

Clear Error Messages

In interactive components, show specific error messages near the field, not just an alert. When JavaScript is off, users still get a response from the server through a reloaded page with the standard action attribute.

Choose Interactions Wisely

As always in Astro: add JavaScript only if it genuinely adds value. A simple contact form may be fine with pure HTML. A signup form with real-time validation deserves a hydrated component.

Handling Form Submission via Serverless Functions

Using Platform Serverless Functions

For static sites, the /api endpoint is not available on your own server. The solution is a serverless function from the hosting platform. Example on Netlify:

Fungsi serverless Netlify
# netlify/functions/pendaftaran.mjs
export default async (req) => {
  const data = await req.json();
  return new Response("OK", { status: 200 });
};

Serverless functions run on the hosting platform's edge and can receive form submissions from static sites. You can use Vercel Functions, Netlify Functions, or Cloudflare Workers depending on your hosting.

Deciding Where the Data Goes

Form data must go somewhere: email, a database, or a third-party service like Formspree. Choose a service that matches your load and privacy needs — this decision also relates to the security discussed in episode 12.

Warning

Never put data-storage logic directly in a client component. Sensitive data must pass through a server endpoint or a serverless function for validation and protection.

Conclusion

Episode 10 builds the bridge between visitors and site owners: pure HTML forms that work without JavaScript, API endpoints in server mode, interactive form components with hydration, two-layer validation with progressive enhancement, and form submission through serverless functions.

The key takeaways:

  • HTML forms with action and method work without JavaScript.
  • Endpoints in src/pages/api receive submissions with request.formData().
  • Hydrated form components give real-time feedback.
  • Validation is always two-layered: browser and server.
  • Static sites use the platform's serverless functions to process forms.
  • Add JavaScript interaction only when it is genuinely needed.

In the next episode 11, we will cover content management and CMS: integrating headless CMS platforms like Contentful, Sanity, or Strapi, content sourcing from Git-based CMS, preview mode and build-time content updates, and authoring workflows and metadata management. Your content will be managed by a team like a real production.

Learning Astro - Forms & Interactions | Learning Astro