FormWire for Eleventy

Eleventy contact forms, zero client JavaScript.

11ty ships no framework to the browser, and your contact form doesn't need one. A plain form POSTs to one endpoint, and every submission becomes an email in your inbox and a record in your dashboard — while your site stays the fast, script-free HTML you built it to be.

Copy-paste code

An include, a data file, two Markdown pages.

The pieces land where 11ty expects them: the form in _includes, the key in _data, the pages as Markdown with permalinks. The third tab adds an optional fetch upgrade for an inline status message.

{# _includes/contact-form.njk — render it anywhere with
   {% include "contact-form.njk" %} #}
<form action="https://api.formwire.com/submit" method="POST">
  <input type="hidden" name="access_key" value="{{ formwire.accessKey }}">

  {# A static build can't redirect after a POST, so FormWire does it.
     Absolute URL — the endpoint sends the visitor back to your site. #}
  <input type="hidden" name="_redirect" value="{{ formwire.thanksUrl }}">

  <label>
    Name
    <input type="text" name="name" required>
  </label>
  <label>
    Email
    <input type="email" name="email" required>
  </label>
  <label>
    Message
    <textarea name="message" required></textarea>
  </label>
  <button type="submit">Send</button>
</form>

// ─────────────────────────────────────────────────────────────────────
// _data/formwire.js — global data: every template, any engine, can read
// {{ formwire.accessKey }}. The key is public by design, safe to commit.

module.exports = {
  accessKey: "YOUR-ACCESS-KEY",
  thanksUrl: "https://yoursite.com/thanks/",
};

Swap YOUR-ACCESS-KEY for your form's key in _data/formwire.js. The full field and response reference lives in the docs at /docs/.

Eleventy gotchas

The four things that trip up 11ty forms.

Small conventions with outsized consequences. The snippets above already account for all four.

Markdown renders through Liquid by default

Eleventy preprocesses .md files with a template engine, and out of the box that engine is Liquid — so a Nunjucks {% include %} in your contact page fails until you set markdownTemplateEngine: "njk" in the config. One line, but invisible until you know to look for it.

Four spaces of indentation break the form

Raw HTML in Markdown passes through untouched — unless it's indented four or more spaces, which markdown-it treats as a literal code block. Nest the include under a list item and your visitors see the form's source instead of the form. Keep it flush-left.

Match the permalink, trailing slash and all

permalink: /thanks/ writes thanks/index.html, and the canonical URL keeps the trailing slash. Point _redirect at exactly that URL — a mismatched /thanks costs an extra redirect hop on some hosts and a 404 on others.

The zero-JS path is the native path

There's no client framework waiting to intercept the submit, so the plain POST plus _redirect is a complete integration on its own. Add the fetch upgrade only when an inline status message is genuinely better than the thank-you page — it's polish, not plumbing.

Three steps

From nothing to a working form.

  1. Grab your access key

    Create a form in the dashboard and copy its public key into _data/formwire.js. It's a safe-to-commit alias for your verified email.

  2. Save the include, place it anywhere

    Drop contact-form.njk into _includes and render it from a layout, a page template or a Markdown file. The markup and styling stay entirely yours.

  3. Submissions land in your inbox

    Every POST arrives as a formatted email with Reply-To set to the visitor, and as a searchable record in your dashboard.

Why FormWire for Eleventy

Built for a site that ships HTML.

Every template engine, one recipe

The key lives in the data cascade, which Nunjucks, Liquid and every other 11ty engine reads the same way. Only the include syntax changes; the form doesn't.

Spam filtered server-side

The honeypot runs at the endpoint, so a script-free 11ty site keeps bots out of your inbox — and a captcha is one dashboard toggle away if a form gets targeted.

Deploys anywhere your site does

GitHub Pages, Cloudflare Pages, Netlify, a VPS with nginx — the form is static HTML, so the host only needs to serve files. Host-specific form features stay out of the picture.

Every submission stored

Beyond the email, each POST becomes a searchable record with CSV export and a JSON read API — the paper trail a static site otherwise can't keep.

Eleventy form FAQ

The questions 11ty developers actually ask.

Building with another framework?

See all frameworks
Ready in a minute

Ship your Eleventy form today.

Grab an access key, paste an include, and route submissions to your inbox — or on to Slack, Sheets and Zapier.

Free tier forever. No credit card required.