How to Add a Contact Form to Your Jekyll Site
Add a working contact form to Jekyll without a backend — using Formspree, Netlify Forms, or Getform. Setup guides for all three with spam protection tips.
Jekyll generates static HTML — there’s no server-side code to process form submissions. But you don’t need one. Three services handle form submissions for static sites, and all have free tiers that cover most personal and small business needs.
The Three Best Options
| Formspree | Netlify Forms | Getform | |
|---|---|---|---|
| Free submissions | 50/month | 100/month | 100/month |
| Setup difficulty | Very easy | Easy (Netlify only) | Very easy |
| Spam protection | reCAPTCHA, honeypot | Honeypot, Akismet | reCAPTCHA, honeypot |
| File uploads | Paid | Paid | Free |
| Webhooks | Paid | Yes | Yes |
| Works on any host | Yes | Netlify only | Yes |
Option 1: Formspree (Recommended for Most Sites)
Formspree is the simplest option — point your form’s action at a Formspree endpoint and submissions are emailed to you.
Setup
- Sign up at formspree.io (free)
- Click New Form, give it a name
- Copy your form endpoint URL (looks like
https://formspree.io/f/xpzgkwlr)
HTML
<!-- contact.md or _pages/contact.md -->
---
layout: page
title: Contact
permalink: /contact/
---
<form action="https://formspree.io/f/YOUR_FORM_ID" method="POST" class="contact-form">
<div class="form-group">
<label for="name">Name <span aria-hidden="true">*</span></label>
<input type="text" id="name" name="name" required autocomplete="name">
</div>
<div class="form-group">
<label for="email">Email <span aria-hidden="true">*</span></label>
<input type="email" id="email" name="email" required autocomplete="email">
</div>
<div class="form-group">
<label for="subject">Subject</label>
<input type="text" id="subject" name="subject">
</div>
<div class="form-group">
<label for="message">Message <span aria-hidden="true">*</span></label>
<textarea id="message" name="message" rows="6" required></textarea>
</div>
<!-- Honeypot spam protection -->
<input type="text" name="_gotcha" style="display:none">
<!-- Redirect after submission -->
<input type="hidden" name="_next" value="https://yourdomain.com/thank-you/">
<button type="submit" class="btn btn--primary">Send Message</button>
</form>
Create a Thank You Page
Create _pages/thank-you.md:
---
layout: page
title: Message Sent
permalink: /thank-you/
sitemap: false
---
Thanks for getting in touch — I'll reply within 1–2 business days.
AJAX Submission (No Page Redirect)
For a smoother experience, submit with JavaScript:
<form id="contact-form" action="https://formspree.io/f/YOUR_FORM_ID" method="POST">
<!-- form fields as above -->
<button type="submit" id="submit-btn">Send Message</button>
<p id="form-status" style="display:none"></p>
</form>
<script>
const form = document.getElementById('contact-form');
const status = document.getElementById('form-status');
const btn = document.getElementById('submit-btn');
form.addEventListener('submit', async function(e) {
e.preventDefault();
btn.disabled = true;
btn.textContent = 'Sending...';
const data = new FormData(form);
try {
const response = await fetch(form.action, {
method: 'POST',
body: data,
headers: { 'Accept': 'application/json' }
});
if (response.ok) {
form.reset();
status.textContent = "Thanks! I'll be in touch soon.";
status.style.color = 'green';
btn.textContent = 'Sent ✓';
} else {
throw new Error('Server error');
}
} catch (err) {
status.textContent = 'Something went wrong. Please try again.';
status.style.color = 'red';
btn.disabled = false;
btn.textContent = 'Send Message';
}
status.style.display = 'block';
});
</script>
Option 2: Netlify Forms (Best if Hosting on Netlify)
If your Jekyll site is hosted on Netlify, form handling is built in — no third-party service needed.
Setup
Add netlify attribute to your form tag. That’s it:
<form name="contact" method="POST" data-netlify="true" netlify-honeypot="bot-field">
<input type="hidden" name="form-name" value="contact">
<!-- Honeypot -->
<div style="display:none">
<label>Don't fill this out: <input name="bot-field"></label>
</div>
<div class="form-group">
<label for="name">Name</label>
<input type="text" id="name" name="name" required>
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" id="email" name="email" required>
</div>
<div class="form-group">
<label for="message">Message</label>
<textarea id="message" name="message" rows="6" required></textarea>
</div>
<button type="submit">Send</button>
</form>
Netlify detects the data-netlify="true" attribute at build time and registers the form automatically. Submissions appear in your Netlify dashboard under Forms.
Email Notifications
In Netlify Dashboard → Forms → your form → Form notifications, add your email address. You’ll get an email for every submission.
Free Plan Limit
100 form submissions/month on Netlify’s free tier. Enough for most personal sites and small businesses.
Option 3: Getform
Getform is similar to Formspree with a generous free tier.
Setup
- Sign up at getform.io
- Create a form endpoint
- Copy the endpoint URL
<form action="https://getform.io/f/YOUR_ENDPOINT" method="POST">
<input type="text" name="name" placeholder="Name" required>
<input type="email" name="email" placeholder="Email" required>
<textarea name="message" placeholder="Message" required></textarea>
<!-- Honeypot -->
<input type="hidden" name="_gotcha" style="display:none">
<button type="submit">Send</button>
</form>
Styling the Contact Form
// _sass/components/_forms.scss
.contact-form {
max-width: 600px;
}
.form-group {
margin-bottom: 1.25rem;
label {
display: block;
font-weight: 600;
margin-bottom: 0.375rem;
font-size: 0.9rem;
color: var(--text-color);
}
input[type="text"],
input[type="email"],
textarea {
width: 100%;
padding: 0.625rem 0.875rem;
border: 1px solid var(--border-color);
border-radius: var(--radius-md);
background: var(--bg-color);
color: var(--text-color);
font-size: 1rem;
font-family: inherit;
transition: border-color 0.15s;
&:focus {
outline: none;
border-color: var(--color-primary);
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
}
}
textarea {
resize: vertical;
min-height: 140px;
}
}
Spam Protection
All three services include basic spam protection. For extra security:
Honeypot field — A hidden field bots fill in but humans don’t:
<input type="text" name="_gotcha" style="display:none" tabindex="-1" autocomplete="off">
Check for it if processing on your end — any submission where _gotcha is filled is a bot.
reCAPTCHA v3 (Formspree Pro) — Invisible challenge, no checkbox needed. Better UX than v2.
Rate limiting — All three services rate-limit submissions by IP automatically.
Which to Choose
- Formspree — best default choice, works on any host, cleanest setup
- Netlify Forms — best if you’re already on Netlify, no third-party account needed
- Getform — good Formspree alternative with file upload support on free tier
All three have free tiers that handle 50–100 submissions/month — more than enough for contact forms on most sites.
Browse Jekyll themes on JekyllHub — several themes include a pre-styled contact page ready to connect to your form service.