Add a contact form to a Hugo site (no backend)
By Maxime Branger · Published on
Why it is tricky with Hugo
Hugo generates static files. There is nothing on the server side to process a submission. So we will create a shortcode that sends the data to AirMess, and you can insert it into any page.
Step 1: declare the URL in the configuration
In hugo.toml :
[params.airmess]
formUrl = "https://airmess.fr/api/submit/YOUR_TOKEN"Keeping the URL in the configuration lets you change it without touching the templates.
Step 2: create the shortcode
Create layouts/shortcodes/contact.html :
<form id="contact-form" action="{{ site.Params.airmess.formUrl }}" method="POST">
<label for="name">Name</label>
<input id="name" name="name" type="text" required>
<label for="email">Email</label>
<input id="email" name="email" type="email" required>
<label for="message">Message</label>
<textarea id="message" name="message" rows="5" required></textarea>
<button type="submit">Send</button>
<p id="contact-status" role="status"></p>
</form>
<script>
const form = document.querySelector('#contact-form');
const status = document.querySelector('#contact-status');
form.addEventListener('submit', async (e) => {
e.preventDefault();
const button = form.querySelector('button');
button.disabled = true;
status.textContent = 'Sending…';
try {
const res = await fetch(form.action, {
method: 'POST',
body: new FormData(form),
});
if (!res.ok) throw new Error(String(res.status));
form.reset();
status.textContent = 'Thank you, your message has been sent.';
} catch {
status.textContent = "Sending failed. Please try again in a moment.";
} finally {
button.disabled = false;
}
});
</script>Step 3: use it in a page
In content/contact.md :
---
title: "Contact"
---
A question? Write to me.
{{< contact >}}Notes
If your theme blocks inline scripts through a Content Security Policy, move the script to static/js/contact.js and load it with a <script src> tag. When testing with hugo server , make sure your local origin is allowed.
The full code of this tutorial is available on GitHub.