Overview

The template includes three form-related components:

  • Form - Wrapper with validation, honeypot, and status messages
  • Input - Styled input fields with validation states
  • Button - Buttons with multiple variants and sizes

Basic Newsletter Form

A simple newsletter signup form:

---
import Form from "../components/Form.astro";
import Input from "../components/Input.astro";
import Button from "../components/Button.astro";
---

<Form
  action="/api/subscribe"
  name="newsletter"
  successMessage="Thanks for subscribing!"
>
  <div class="form-fields">
    <Input
      type="email"
      name="email"
      label="Email address"
      placeholder="you@example.com"
      required
    />
    <Button type="submit" variant="primary">
      Subscribe
    </Button>
  </div>
</Form>

Live Example

Status Messages

The Form component displays success and error messages automatically after submission. Here's what they look like:

Success Message:

Thank you! Your submission has been received.

Error Message:

Something went wrong. Please try again.

Customize messages via props:

<Form
  action="/api/contact"
  successMessage="We'll be in touch soon!"
  errorMessage="Failed to send. Please email us directly."
>
  <!-- form fields -->
</Form>

Form Component Props

Prop Type Default Description
action string "" Form submission URL
method "POST" | "GET" "POST" HTTP method
name string "contact" Form name (required for Netlify)
successMessage string "Thank you!..." Message shown on success
errorMessage string "Something went wrong..." Message shown on error
netlify boolean false Enable Netlify Forms
redirectUrl string - Redirect after success

Input Component Props

Prop Type Default Description
type "text" | "email" | "password" | "tel" | "textarea" | ... "text" Input type
name string required Field name
label string - Label text
placeholder string - Placeholder text
required boolean false Required field
error string - Error message
helpText string - Help text below input
disabled boolean false Disable input

Button Component Props

Prop Type Default Description
variant "primary" | "secondary" | "outline" | "ghost" "primary" Button style
size "sm" | "md" | "lg" "md" Button size
href string - Render as link
type "button" | "submit" | "reset" "button" Button type
fullWidth boolean false Full width button
loading boolean false Show loading spinner
disabled boolean false Disable button

Button Variants

Contact Form Example

<Form action="/api/contact" name="contact">
  <div class="form-fields">
    <Input
      type="text"
      name="name"
      label="Name"
      required
    />
    <Input
      type="email"
      name="email"
      label="Email"
      required
    />
    <Input
      type="textarea"
      name="message"
      label="Message"
      rows={5}
      required
    />
    <Button type="submit" variant="primary" fullWidth>
      Send Message
    </Button>
  </div>
</Form>

Spam Protection (Honeypot)

The Form component includes built-in honeypot spam protection. Here's how it works:

1
Hidden field added automatically

A hidden input field is injected into every form, invisible to humans but visible to bots.

2
Bots fill all fields

Automated bots typically fill out every field they find, including the hidden one.

3
Submission blocked silently

If the hidden field has a value, we know it's a bot. The form shows "success" but nothing is sent.

Generated HTML:

<!-- Automatically added to every Form -->
<div class="form-honeypot" aria-hidden="true">
  <label for="contact-hp">Don't fill this out</label>
  <input
    type="text"
    name="contact_hp"
    id="contact-hp"
    tabindex="-1"
    autocomplete="off"
  />
</div>

CSS that hides it from humans:

.form-honeypot {
  position: absolute;
  left: -9999px;
  top: -9999px;
  opacity: 0;
  pointer-events: none;
  height: 0;
  overflow: hidden;
}

JavaScript that checks it:

// If honeypot is filled, it's a bot
const honeypot = form.querySelector('[name$="_hp"]');
if (honeypot && honeypot.value) {
  // Show fake success, but don't actually submit
  showSuccess();
  return;
}

For additional protection, consider:

  • Rate limiting on your API endpoint
  • CAPTCHA integration (hCaptcha, Turnstile)
  • Server-side validation

Using with Netlify Forms

<Form
  name="contact"
  netlify={true}
  successMessage="Thanks! We'll be in touch."
>
  <!-- form fields -->
</Form>

When netlify={true}, the component adds data-netlify="true" to the form element.

Using with Formspree

<Form
  action="https://formspree.io/f/YOUR_FORM_ID"
  name="contact"
>
  <!-- form fields -->
</Form>

Using with Web3Forms

Web3Forms is a free, no-backend form solution. Get your access key from the dashboard.

<Form
  action="https://api.web3forms.com/submit"
  name="contact"
>
  <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
  <!-- form fields -->
</Form>

Features:

  • Free tier: 250 submissions/month
  • No account required for basic usage
  • Email notifications included
  • Spam protection via hCaptcha (optional)