Skip to content

Forminit + Middleman Integration Guide

Middleman is a Ruby-based static site generator that outputs plain HTML files with no server-side processing. Forminit handles all form submissions through our client-side SDK, making it a perfect match for Middleman sites.

What you’ll get:

  • Accept form submissions without building a backend
  • Email notifications for new submissions
  • Spam protection (reCAPTCHA, hCaptcha, honeypot)
  • File uploads support
  • Submission dashboard to manage responses

Requirements:

  • A Middleman site (v4.0+)
  • Ruby 2.5+ and RubyGems
  • A Forminit account and Form ID

  1. Sign up or log in at forminit.com
  2. Create a new form
  3. Go to Form Settings → Set authentication mode to Public
  4. Copy your Form ID (e.g., YOUR-FORM-ID)

Store your Form ID in config.rb:

# config.rb

set :forminit_form_id, 'YOUR-FORM-ID'

Or use environment variables:

# config.rb

set :forminit_form_id, ENV['FORMINIT_FORM_ID'] || 'YOUR-FORM-ID'

Create a .env file (use dotenv gem):

FORMINIT_FORM_ID=Xk9mP2nQ1r

Create a partial for your contact form:

<!-- source/partials/_contact_form.html.erb -->

<form id="contact-form">
  <div class="form-group">
    <label for="firstName">First Name</label>
    <input 
      type="text" 
      id="firstName" 
      name="fi-sender-firstName" 
      placeholder="John" 
      required 
    />
  </div>

  <div class="form-group">
    <label for="lastName">Last Name</label>
    <input 
      type="text" 
      id="lastName" 
      name="fi-sender-lastName" 
      placeholder="Doe" 
      required 
    />
  </div>

  <div class="form-group">
    <label for="email">Email</label>
    <input 
      type="email" 
      id="email" 
      name="fi-sender-email" 
      placeholder="john@example.com" 
      required 
    />
  </div>

  <div class="form-group">
    <label for="message">Message</label>
    <textarea 
      id="message" 
      name="fi-text-message" 
      placeholder="Your message..." 
      rows="5" 
      required
    ></textarea>
  </div>

  <button type="submit">Send Message</button>
</form>

<p id="form-status"></p>
-# source/partials/_contact_form.html.haml

%form#contact-form
  .form-group
    %label{for: "firstName"} First Name
    %input{type: "text", id: "firstName", name: "fi-sender-firstName", placeholder: "John", required: true}
  
  .form-group
    %label{for: "lastName"} Last Name
    %input{type: "text", id: "lastName", name: "fi-sender-lastName", placeholder: "Doe", required: true}
  
  .form-group
    %label{for: "email"} Email
    %input{type: "email", id: "email", name: "fi-sender-email", placeholder: "john@example.com", required: true}
  
  .form-group
    %label{for: "message"} Message
    %textarea{id: "message", name: "fi-text-message", placeholder: "Your message...", rows: 5, required: true}
  
  %button{type: "submit"} Send Message

%p#form-status
/ source/partials/_contact_form.html.slim

form#contact-form
  .form-group
    label for="firstName" First Name
    input type="text" id="firstName" name="fi-sender-firstName" placeholder="John" required=true
  
  .form-group
    label for="lastName" Last Name
    input type="text" id="lastName" name="fi-sender-lastName" placeholder="Doe" required=true
  
  .form-group
    label for="email" Email
    input type="email" id="email" name="fi-sender-email" placeholder="john@example.com" required=true
  
  .form-group
    label for="message" Message
    textarea id="message" name="fi-text-message" placeholder="Your message..." rows=5 required=true
  
  button type="submit" Send Message

p#form-status

Create a partial for the form script:

<!-- source/partials/_forminit_script.html.erb -->

<script src="https://forminit.com/sdk/v1/forminit.js"></script>

<script>
  const forminit = new Forminit();
  const FORM_ID = '<%= config[:forminit_form_id] %>';

  const form = document.getElementById('contact-form');
  const status = document.getElementById('form-status');

  form.addEventListener('submit', async function(event) {
    event.preventDefault();
    
    // Show loading state
    status.textContent = 'Sending...';
    status.className = 'status-loading';

    const formData = new FormData(form);
    const { data, error } = await forminit.submit(FORM_ID, formData);

    if (error) {
      status.textContent = error.message;
      status.className = 'status-error';
      return;
    }

    // Success
    status.textContent = 'Message sent successfully!';
    status.className = 'status-success';
    form.reset();
  });
</script>

Add the script partial to your layout before </body>:

<!-- source/layouts/layout.html.erb -->

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title><%= current_page.data.title || 'My Site' %></title>
  <%= stylesheet_link_tag 'site' %>
</head>
<body>
  <%= partial 'partials/header' %>
  
  <main>
    <%= yield %>
  </main>
  
  <%= partial 'partials/footer' %>
  
  <% if current_page.data.has_form %>
    <%= partial 'partials/forminit_script' %>
  <% end %>
</body>
</html>

Create a contact page that uses the form:

---
title: Contact
has_form: true
---

<div class="contact-page">
  <h1>Contact Us</h1>
  <p>We'd love to hear from you. Fill out the form below and we'll get back to you soon.</p>
  
  <%= partial 'partials/contact_form' %>
</div>

Store form configuration in Middleman’s data folder:

# data/forms.yml

contact:
  id: "Xk9mP2nQ1r"
  success_message: "Thanks for reaching out!"

newsletter:
  id: "aB3cD5eF7g"
  success_message: "You're subscribed!"

application:
  id: "T4vWx8yZ0q"
  success_message: "Application received!"

Access in your templates:

const FORM_ID = '<%= data.forms.contact.id %>';

For a complete list of available form blocks (text, email, phone, file, rating, select, etc.) and field naming patterns, see the Form Blocks documentation.


<!-- source/partials/_contact_form.html.erb -->

<form id="contact-form">
  <input type="text" name="fi-sender-firstName" placeholder="First name" required />
  <input type="text" name="fi-sender-lastName" placeholder="Last name" required />
  <input type="email" name="fi-sender-email" placeholder="Email" required />
  
  <select name="fi-select-subject" required>
    <option value="">Select a subject</option>
    <option value="general">General Inquiry</option>
    <option value="support">Support</option>
    <option value="sales">Sales</option>
    <option value="partnership">Partnership</option>
  </select>
  
  <textarea name="fi-text-message" placeholder="Your message" required></textarea>
  
  <button type="submit">Send</button>
</form>

<p id="form-status"></p>
<!-- source/partials/_newsletter_form.html.erb -->

<form id="newsletter-form">
  <input type="email" name="fi-sender-email" placeholder="Enter your email" required />
  <button type="submit">Subscribe</button>
</form>

<p id="newsletter-status"></p>

<script src="https://forminit.com/sdk/v1/forminit.js"></script>
<script>
  const forminit = new Forminit();
  const FORM_ID = '<%= data.forms.newsletter.id %>';

  const form = document.getElementById('newsletter-form');
  const status = document.getElementById('newsletter-status');

  form.addEventListener('submit', async function(event) {
    event.preventDefault();
    status.textContent = 'Subscribing...';

    const formData = new FormData(form);
    const { data, error } = await forminit.submit(FORM_ID, formData);

    if (error) {
      status.textContent = error.message;
      return;
    }

    status.textContent = 'Thank you for subscribing!';
    form.reset();
  });
</script>
<!-- source/partials/_feedback_form.html.erb -->

<form id="feedback-form">
  <input type="email" name="fi-sender-email" placeholder="Email (optional)" />
  
  <fieldset>
    <legend>How would you rate your experience?</legend>
    <% (1..5).each do |n| %>
      <label>
        <input type="radio" name="fi-rating-experience" value="<%= n %>" />
        <%= n %>
      </label>
    <% end %>
  </fieldset>
  
  <textarea name="fi-text-feedback" placeholder="Tell us more (optional)"></textarea>
  
  <button type="submit">Submit Feedback</button>
</form>

<p id="feedback-status"></p>
<!-- source/partials/_application_form.html.erb -->

<form id="application-form">
  <input type="text" name="fi-sender-firstName" placeholder="First name" required />
  <input type="text" name="fi-sender-lastName" placeholder="Last name" required />
  <input type="email" name="fi-sender-email" placeholder="Email" required />
  <input type="tel" name="fi-sender-phone" placeholder="Phone (+1234567890)" />
  
  <input type="url" name="fi-url-linkedin" placeholder="LinkedIn profile URL" />
  <input type="url" name="fi-url-portfolio" placeholder="Portfolio URL" />
  
  <select name="fi-select-position" required>
    <option value="">Select position</option>
    <option value="frontend">Frontend Developer</option>
    <option value="backend">Backend Developer</option>
    <option value="fullstack">Full Stack Developer</option>
    <option value="designer">UI/UX Designer</option>
  </select>
  
  <label>
    Resume (PDF)
    <input type="file" name="fi-file-resume" accept=".pdf" required />
  </label>
  
  <label>
    Cover Letter (optional)
    <input type="file" name="fi-file-cover_letter" accept=".pdf,.doc,.docx" />
  </label>
  
  <textarea name="fi-text-why_join" placeholder="Why do you want to join us?"></textarea>
  
  <button type="submit">Submit Application</button>
</form>

<p id="application-status"></p>

Create custom helpers in config.rb for cleaner templates:

# config.rb

helpers do
  def forminit_form_id(form_name = :contact)
    data.forms[form_name]&.id || config[:forminit_form_id]
  end
  
  def forminit_script(form_element_id, form_name = :contact)
    <<~HTML
      <script src="https://forminit.com/sdk/v1/forminit.js"></script>
      <script>
        const forminit = new Forminit();
        const FORM_ID = '#{forminit_form_id(form_name)}';
        const form = document.getElementById('#{form_element_id}');
        const status = document.getElementById('#{form_element_id}-status');
        
        form.addEventListener('submit', async function(event) {
          event.preventDefault();
          status.textContent = 'Sending...';
          
          const formData = new FormData(form);
          const { data, error } = await forminit.submit(FORM_ID, formData);
          
          if (error) {
            status.textContent = error.message;
            status.className = 'status-error';
            return;
          }
          
          status.textContent = 'Message sent successfully!';
          status.className = 'status-success';
          form.reset();
        });
      </script>
    HTML
  end
end

Use in templates:

<form id="contact-form">
  <!-- form fields -->
</form>
<p id="contact-form-status"></p>

<%= forminit_script('contact-form', :contact) %>

The SDK returns { data, redirectUrl, error }:

On success:

{
  data: {
    hashId: "7LMIBoYY74JOCp1k",      // Unique submission ID
    date: "2026-01-01 21:10:24",      // Timestamp
    blocks: {                          // Submitted values
      sender: {
        firstName: "John",
        lastName: "Doe",
        email: "john@example.com"
      },
      message: "Hello from Middleman!"
    }
  },
  redirectUrl: "https://forminit.com/thank-you"
}

On error:

{
  error: {
    error: "ERROR_CODE",
    code: 400,
    message: "Human-readable error message"
  }
}

If you prefer to redirect users to a thank-you page:

form.addEventListener('submit', async function(event) {
  event.preventDefault();

  const formData = new FormData(form);
  const { data, redirectUrl, error } = await forminit.submit(FORM_ID, formData);

  if (error) {
    status.textContent = error.message;
    return;
  }

  // Redirect to thank-you page
  window.location.href = '/thank-you/';
  // Or use Forminit's redirect URL:
  // window.location.href = redirectUrl;
});

Create a thank-you page:

---
title: Thank You
---

<h1>Thank You!</h1>
<p>Thank you for your message! We'll get back to you soon.</p>
<p><a href="/">← Back to Home</a></p>

Here’s a typical Middleman project structure with Forminit forms:

my-middleman-site/
├── config.rb                      # Site config with Form ID
├── data/
│   └── forms.yml                  # Form configurations
├── source/
│   ├── images/
│   ├── javascripts/
│   ├── layouts/
│   │   └── layout.html.erb        # Base layout
│   ├── partials/
│   │   ├── _contact_form.html.erb
│   │   ├── _forminit_script.html.erb
│   │   ├── _header.html.erb
│   │   └── _footer.html.erb
│   ├── stylesheets/
│   │   └── site.css.scss
│   ├── contact.html.erb           # Contact page
│   ├── thank-you.html.erb         # Thank you page
│   └── index.html.erb             # Homepage
├── Gemfile
└── Gemfile.lock

Build your static site:

bundle exec middleman build

The generated files will be in the build/ directory, ready to deploy to any static hosting service like Netlify, Vercel, or AWS S3.


  1. View your submissions in the Forminit dashboard
  2. Set up email notifications for new submissions
  3. Explore webhook integrations for advanced workflows