← All Guides

Astro Forms

Add forms to your Astro site with zero JavaScript or interactive islands.

3 minutes Beginner friendly

Prerequisites

Option 1: Embed Script (Easiest)

Zero JavaScript, works with static builds.

Just add the embed script to any Astro page or component:

src/pages/contact.astro

---
import Layout from '../layouts/Layout.astro';
---

<Layout title="Contact">
  <h1>Contact Us</h1>

  <!-- codaForms embed - that's it! -->
  <script src="https://codasite.ai/forms-embed.js" data-form="cf_xxxxx"></script>
</Layout>

Option 2: Astro Component

Custom styling with client-side JavaScript.

src/components/ContactForm.astro

---
interface Props {
  formId: string;
}

const { formId } = Astro.props;
---

<form id="contact-form" class="space-y-4">
  <input
    name="name"
    placeholder="Name"
    required
    class="w-full p-3 rounded-lg bg-gray-800 border border-gray-700"
  />
  <input
    name="email"
    type="email"
    placeholder="Email"
    required
    class="w-full p-3 rounded-lg bg-gray-800 border border-gray-700"
  />
  <textarea
    name="message"
    placeholder="Message"
    rows="4"
    required
    class="w-full p-3 rounded-lg bg-gray-800 border border-gray-700"
  ></textarea>
  <button
    type="submit"
    class="w-full p-3 bg-blue-600 rounded-lg hover:bg-blue-700"
  >
    Send Message
  </button>
</form>

<div id="success-message" class="hidden p-6 bg-green-500/10 rounded-lg text-center">
  <p class="text-green-400">Thanks! We'll be in touch soon.</p>
</div>

<script define:vars={{ formId }}>
  const form = document.getElementById('contact-form');
  const successMessage = document.getElementById('success-message');

  form.addEventListener('submit', async (e) => {
    e.preventDefault();

    const formData = new FormData(form);
    const data = {
      _formId: formId,
      name: formData.get('name'),
      email: formData.get('email'),
      message: formData.get('message'),
    };

    try {
      const res = await fetch('https://codasite.ai/forms/api/submit', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(data),
      });

      const result = await res.json();

      if (result.success) {
        form.classList.add('hidden');
        successMessage.classList.remove('hidden');
      } else {
        alert('Something went wrong. Please try again.');
      }
    } catch (error) {
      alert('Something went wrong. Please try again.');
    }
  });
</script>

Use it in any page:

---
import Layout from '../layouts/Layout.astro';
import ContactForm from '../components/ContactForm.astro';
---

<Layout title="Contact">
  <h1>Contact Us</h1>
  <ContactForm formId="cf_xxxxx" />
</Layout>

Option 3: React Island

Use React for complex interactive forms.

If you need React-level interactivity, create an island component:

src/components/ContactForm.tsx

import { useState } from 'react';

export default function ContactForm({ formId }: { formId: string }) {
  const [status, setStatus] = useState<'idle' | 'submitting' | 'success'>('idle');

  async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault();
    setStatus('submitting');

    const formData = new FormData(e.currentTarget);

    const res = await fetch('https://codasite.ai/forms/api/submit', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        _formId: formId,
        name: formData.get('name'),
        email: formData.get('email'),
        message: formData.get('message'),
      }),
    });

    const result = await res.json();
    if (result.success) setStatus('success');
  }

  if (status === 'success') {
    return <p>Thanks! We'll be in touch soon.</p>;
  }

  return (
    <form onSubmit={handleSubmit}>
      <input name="name" placeholder="Name" required />
      <input name="email" type="email" placeholder="Email" required />
      <textarea name="message" placeholder="Message" required />
      <button disabled={status === 'submitting'}>
        {status === 'submitting' ? 'Sending...' : 'Send'}
      </button>
    </form>
  );
}

src/pages/contact.astro

---
import Layout from '../layouts/Layout.astro';
import ContactForm from '../components/ContactForm';
---

<Layout title="Contact">
  <h1>Contact Us</h1>
  <ContactForm client:load formId="cf_xxxxx" />
</Layout>

Ready to get started?

Create your first form in under 2 minutes.

Create Free Account