Back to blog

    How to Add a Contact Form to an Eleventy (11ty) Site

    Eleventy generates static HTML — there's no backend to receive form submissions. Here's how to add a working contact form to any 11ty site in minutes, no serverless functions needed.

    How to Add a Contact Form to an Eleventy (11ty) Site

    Eleventy (11ty) is a static site generator — it outputs pure HTML with no server-side runtime. That means no built-in way to handle form submissions. This guide shows how to add a contact form to any 11ty site that works on any host, without writing a serverless function.

    Step 1: Create a Formboost Endpoint

    Sign up at dashboard.formboost.app and create a new endpoint. You'll get a URL like:

    https://formboost.app/f/YOUR_ENDPOINT_ID

    Step 2: Create a Contact Page

    Create contact.njk (or contact.html, contact.liquid) in your Eleventy source directory:

    1---
    2layout: base.njk
    3title: Contact
    4permalink: /contact/
    5---
    6
    7<h1>Contact Us</h1>
    8
    9<form action="https://formboost.app/f/YOUR_ENDPOINT_ID" method="POST">
    10  <!-- Honeypot: bots fill this in, humans don't see it -->
    11  <input type="text" name="_honey" style="display:none" tabindex="-1" autocomplete="off" />
    12
    13  <div>
    14    <label for="name">Name</label>
    15    <input type="text" id="name" name="name" required />
    16  </div>
    17
    18  <div>
    19    <label for="email">Email</label>
    20    <input type="email" id="email" name="email" required />
    21  </div>
    22
    23  <div>
    24    <label for="message">Message</label>
    25    <textarea id="message" name="message" rows="6"></textarea>
    26  </div>
    27
    28  <button type="submit">Send Message</button>
    29</form>

    Replace YOUR_ENDPOINT_ID with your actual endpoint ID.

    Step 3: Add a Thank-You Page (Optional)

    By default, Formboost redirects to a hosted confirmation page after submission. To use your own 11ty page:

    Add a hidden field in the form:

    1<input type="hidden" name="_redirect" value="https://yoursite.com/thank-you/" />

    Create thank-you.njk:

    1---
    2layout: base.njk
    3title: Message Sent
    4permalink: /thank-you/
    5---
    6
    7<h1>Message received!</h1>
    8<p>Thanks for reaching out. We'll get back to you soon.</p>
    9<a href="/">← Back to home</a>

    Step 4: Create a Reusable Shortcode

    In Eleventy, you can create a reusable shortcode to embed the form on any page. Add this to your .eleventy.js config:

    1// .eleventy.js
    2module.exports = function(eleventyConfig) {
    3  eleventyConfig.addShortcode("contactForm", function(endpointId) {
    4    return `
    5      <form action="https://formboost.app/f/${endpointId}" method="POST">
    6        <input type="text" name="_honey" style="display:none" tabindex="-1" autocomplete="off" />
    7        <div>
    8          <label for="name">Name</label>
    9          <input type="text" id="name" name="name" required />
    10        </div>
    11        <div>
    12          <label for="email">Email</label>
    13          <input type="email" id="email" name="email" required />
    14        </div>
    15        <div>
    16          <label for="message">Message</label>
    17          <textarea id="message" name="message" rows="5"></textarea>
    18        </div>
    19        <button type="submit">Send</button>
    20      </form>
    21    `;
    22  });
    23
    24  return { dir: { input: "src", output: "_site" } };
    25};

    Then use it in any template:

    1{% contactForm "YOUR_ENDPOINT_ID" %}

    Step 5: Use Nunjucks Data for Dynamic Fields

    Pass page context to the form using Eleventy's template data:

    1<input type="hidden" name="source_page" value="{{ page.url }}" />

    This records which 11ty page each submission came from — useful if you embed the form on multiple pages.

    AJAX Submit (Stay on Page)

    To avoid a page redirect on submit, handle the form with JavaScript:

    1<form id="contact-form">
    2  <input type="text" name="name" required placeholder="Name" />
    3  <input type="email" name="email" required placeholder="Email" />
    4  <textarea name="message" rows="5"></textarea>
    5  <button type="submit">Send</button>
    6  <p id="status" hidden></p>
    7</form>
    8
    9<script>
    10  document.getElementById('contact-form').addEventListener('submit', async function(e) {
    11    e.preventDefault();
    12    const data = Object.fromEntries(new FormData(this));
    13    const status = document.getElementById('status');
    14
    15    try {
    16      const res = await fetch('https://formboost.app/f/YOUR_ENDPOINT_ID', {
    17        method: 'POST',
    18        headers: { 'Content-Type': 'application/json' },
    19        body: JSON.stringify(data),
    20      });
    21
    22      status.textContent = res.ok
    23        ? 'Message sent! We\'ll be in touch.'
    24        : 'Something went wrong. Please try again.';
    25      status.style.color = res.ok ? 'green' : 'red';
    26      if (res.ok) this.reset();
    27    } catch {
    28      status.textContent = 'Something went wrong.';
    29      status.style.color = 'red';
    30    }
    31
    32    status.hidden = false;
    33  });
    34</script>

    Get your free Formboost endpoint →