CatchForm

Contact Form for Hugo

Build a contact form partial for your Hugo site that sends submissions directly to your email without any backend server.

Overview

This guide shows how to create a reusable contact form partial in Hugo that works without a backend. The form sends submissions directly to CatchForm, which delivers them to your inbox.

Prerequisites

  • A Hugo site (v0.100 or later)
  • A CatchForm account with an active form

Step 1: Set Up CatchForm

Sign up for CatchForm and create a new form. You'll receive a unique token. Store it in your Hugo site's config or pass it via parameters.

Option A: Add it to your config file (hugo.toml):

[params]
catchformToken = "your-token-here"

Step 2: Create the Contact Form Partial

Create a new file layouts/partials/contact-form.html:

<form
  action="https://catchform.dev/f/{{ .Site.Params.catchformToken }}"
  method="POST"
  class="contact-form"
>
  <input
    type="hidden"
    name="_gotcha"
    value=""
  >

  <div class="form-group">
    <label for="name">Name</label>
    <input
      id="name"
      type="text"
      name="name"
      required
    >
  </div>

  <div class="form-group">
    <label for="email">Email</label>
    <input
      id="email"
      type="email"
      name="email"
      required
    >
  </div>

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

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

<style>
  .contact-form {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
    max-width: 500px;
  }

  .form-group {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
  }

  .contact-form label {
    font-weight: 500;
    font-size: 0.95rem;
  }

  .contact-form input,
  .contact-form textarea {
    padding: 0.625rem;
    border: 1px solid #ddd;
    border-radius: 4px;
    font-family: inherit;
    font-size: 1rem;
  }

  .contact-form input:focus,
  .contact-form textarea:focus {
    outline: none;
    border-color: #4f46e5;
    box-shadow: 0 0 0 2px rgba(79, 70, 229, 0.1);
  }

  .contact-form button {
    padding: 0.75rem 1.5rem;
    background-color: #4f46e5;
    color: white;
    border: none;
    border-radius: 4px;
    font-weight: 600;
    cursor: pointer;
    font-size: 1rem;
  }

  .contact-form button:hover {
    background-color: #4338ca;
  }

  .contact-form button:active {
    transform: scale(0.98);
  }
</style>

Step 3: Use the Partial

Include the partial in any layout or content page using the partial function:


<!-- layouts/contact.html or content/contact/_index.md -->
{{ define "main" }}
  <main>
    <h1>{{ .Title }}</h1>
    {{ .Content }}
    {{ partial "contact-form" . }}
  </main>
{{ end }}

In Markdown files, use shortcodes to include the partial:


{{< partial "contact-form" . >}}

Customization

Add a Success Message

After form submission, redirect the user to a success page. In your CatchForm dashboard, configure the redirect URL (e.g., /thank-you), then create a corresponding Hugo page.

Add More Fields

Simply add more form groups to the partial. Change the name attribute to customize how the field appears in your email:

<div class="form-group">
  <label for="phone">Phone</label>
  <input
    id="phone"
    type="tel"
    name="phone"
  >
</div>

Pass Token as Parameter

If you prefer not to store the token in config, pass it as a parameter to the partial:


<!-- In your layout file -->
{{ partial "contact-form" (dict "token" "your-token-here") }}

<!-- In the partial -->
<form action="https://catchform.dev/f/{{ .token }}" method="POST">
  ...
</form>

Style with Your Theme

The partial uses inline scoped styles. Replace them with your theme's CSS or remove the <style> block and style via your external stylesheet.

Pro Tips

File Attachments

Pro plan users can accept file uploads. Add an input with type="file" and add enctype="multipart/form-data" to the form. Allowed types: JPEG, PNG, GIF, PDF. Maximum size: 5 MB.

Validation

The form uses HTML5 validation attributes (required, type="email"). Browsers enforce these, but CatchForm also validates on the server side.

Spam Protection

The honeypot field is already included in the partial. Bots will fill it and their submissions will be rejected automatically.

Next Steps

Your form is now live. Check your inbox for submissions. Need more help?