Form Components
Build accessible forms with validation, error states, and spam protection.
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:
Error Message:
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:
A hidden input field is injected into every form, invisible to humans but visible to bots.
Automated bots typically fill out every field they find, including the hidden one.
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)