Adding a Netlify contact form to a Hugo static site

on June 29, 2023

I redid my static site’s contact form with a free option from my host, Netlify.

Here’s why I changed my static site host and how I got a Netlify contact form to work with a blog built on Hugo and the Mainroad theme.

Why I moved to Netlify

I wrote back in 2021 about Moving From WordPress to an Azure static site with Hugo. Since then, I migrated away from Azure Static Sites to Netlify’s free plan.

I moved to Netlify for a couple of reasons:

1. I was hitting storage quotas with the Azure static site that caused deployments to fail.

I’d already reduced image file sizes where it made sense and moved larger files off to 3rd party services for hosting and embedding. There was little advice on troubleshooting this issue in Azure, and I have a lot of hobbies to tend to.

Netlify’s free plan doesn’t have this limitation.

2. Netlify offers some other cool things on the free plan, such as the ability to use interactive forms hosted on their servers.

While I’d previously set up a simple option embedding a Google form on my contact page, I didn’t love the workflow with this solution. I wanted something better.

I probably should have blogged about how I migrated to Netlify, if only because it was so simple that I barely remember what I did. I remember that Netlify walked me through everything, and that it was quite easy. I don’t think I even had to provide a credit card number in the process.

It took me a while to get around to redoing my contact form, and here’s how I did it.

Enable form detection in Netlify

First, you’ll need to enable forms in your Netlify site configuration.

  1. Sign into the Netlify UI, then go to Site configuration -> Forms.
  2. Select Enable form detection.

This won’t do anything right away. The next time you deploy the site, Netlify will look for forms which want to hook up.

Start serving your site locally

From a terminal, I ran: hugo serve

I then regularly referred to my locally served version of the site as I stepped through the following. This helped me check functionality as I saved changes to ensure I knew what was working.

Create a Hugo html layout for your contact page form

While there are several posts and tutorials out there on how to do this, I hadn’t worked with Hugo in a minute. I had to spend some time remembering how this all works, and which files I even use for html. Oh, right, the magic happens in Go templates!

Under my layouts folder, I added a new folder, contact. In this folder I created a new file named single.html.

graph LR C["๐Ÿ“ content"] --> layouts["๐Ÿ“ layouts"] --> single-html["single.html"]
{{ define "main" }}
<main class="main" role="main">

 <form name="contact" class="contact-form width-normal" action="/contact-thank-you/" method="POST" data-netlify="true" netlify-honeypot="bot-field">
  <input type="hidden" name="form-name" value="contact" />
  <p class="hidden">
   <label><input name="bot-field" /></label>
  </p>
  <div class="form-group">
   <!-- Text input-->
   <label class="contact-form-1 control-label" for="Name"></label>
   <div class="contact-form-1">
    <input id="contact-form-name" name="Name" type="text" placeholder="Name" class="form-control input-md" required="" autocomplete="off" maxlength="100">
   </div>
   <!-- Text input-->
   <label class="contact-form-1 control-label" for="Email"></label>
   <div class="contact-form-1">
    <input id="contact-form-email" name="Email" type="email" placeholder="Email" class="form-control input-md" required="" autocomplete="off" maxlength="100">
   </div>
   <!-- Text input-->
   <label class="contact-form-1 control-label" for="Subject"></label>
   <div class="contact-form-1">
    <input id="contact-form-subject" name="Subject" type="text" placeholder="Subject" class="form-control input-md" required="" autocomplete="off" maxlength="200">
   </div>
   <!-- Textarea -->
   <label class="contact-form-1 control-label" for=""></label>
   <textarea class="form-control" id="contact-form-message" name="Message" placeholder="What's up?" rows="8"></textarea>
   <!-- Button -->
   <button class="contact-button" type="submit" value="Submit" id="Form-submit">Submit</button>
  </div>
 </form>
</main>

{{ partial "authorbox.html" . }}
{{ partial "pager.html" . }}

{{ end }}

Some notes on this form:

  • The form opening tag specifies data-netlify=“true”. This means that the next time you publish the site, the form may be detected by Netlify, as long as you’ve enabled forms on the site.
  • The form opening tag specifies netlify-honeypot=“bot-field”. There is also an input named bot-field that has a css class specified named hidden. Together, these are used as a spam reduction feature in Netlify.

At this point, as long as you don’t already have a contact folder which this template would apply to, you shouldn’t notice any differences in your locally served copy of your site.

Create a contact page that references the layout

If I was adding a new contact page, I could have added a new folder named content/contact. This would automatically pick up the contact template.

However, I already had a contact page in place with a URL I wanted to maintain that didn’t involve a “contact” subfolder, so I edited my existing file which I had under content/contact-kendra-little.md.

graph LR C["๐Ÿ“ content"] --> contact["๐Ÿ“ contact"] --> contactkendra["contact-kendra-little.md"]

The entire definition of this page is as follows. The important bit is that I added the line type: contact to the front matter so that it will pick up that layout.

---
title: "Contact"
draft: false
authorbox: false
pager: false
menu: main
type: contact
---

At this point, your locally served copy of the site should have a contact form which displays the html form in the template.

The styling, however, may look a little wonky. Mine sure did. And if you don’t have any css already that hides fields with a class named hidden, you will also see the honeypot field on your form, which will look odd.

Add css styling as needed

The next thing I had to remember was where to customize css files. At this point, I realized I could ask GitHub Copilot for help:

I asked copilot a LOT of questions to get my css right, and I&rsquo;m not a bit embarrassed.

I asked copilot a LOT of questions to get my css right, and I’m not a bit embarrassed.

I already had a file named static/css/custom.css, because I’ve learned this before. (I’m sure I’ll not use this for six months and then learn it again.) But create one if you don’t have one already.

graph LR C["๐Ÿ“ content"] --> static["๐Ÿ“ static"] --> css["๐Ÿ“ css"] --> custom-css["custom.css"]

I added the following css to get my form working, using my locally served copy of the site as I made changes.

  .hidden {
    display: none;
  }

  .contact-form-1 input[type="text"],
  .contact-form-1 input[type="email"],
  textarea {
    font-family:'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
    font-size: 1rem;
  }

  /* Add a background color and padding */
  .contact-form-1   {
    max-width: 90%;
    padding-top: 6px;
    padding-bottom: 6px;
    border-radius: 5px;
  }

  /* Style the submit button  */
  .contact-button {
    background-color: #ff8400;
    color: white;
    padding: 4px 4px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
  }

.contact-button:hover {
    background-color: #ff5100;
  }

Create a thank-you page (optional)

My form declaration specifies action="/contact-thank-you/".

graph LR C["๐Ÿ“ content"] --> custom-css["contact-thank-you.md"]

I created a page at content/contact-thank-you.md with the following definition:

---
title: "Thanks for getting in touch"
draft: false
authorbox: false
pager: false
---

I try to reply to most emails within a few business days.

{{< figure src="/images/contact-kendra-little.jpg" width="650" >}}

Commit your changes and deploy the site

To actually test the form, you need to commit your changes and deploy your site. You can do this a bunch of ways with Netlify– go with whatever you are comfortable with, and which meets the requirements of your site.

Configure email notifications for form submissions

I want to get an email when someone fills out the contact form on my site. You can configure this in the Netlify UI by enabling email notifications for one or more forms. Essentially:

  • Log into Netlify.
  • Go to Site configuration -> Forms -> Form notifications.
  • Select Add notification, then step through the wizard to configure the notification.

Test and troubleshoot

Now test out using the form on your published site, and make sure you get the email.

Netlify provides troubleshooting tips if you run into problems.

I used the following sources as references when setting this up: