Hugo Integration
Hugo is a fast static site generator. This guide shows you how to add Kollect forms to your Hugo site.
Basic Contact Form
Create a contact page template:
<!-- layouts/contact/single.html -->
{{ define "main" }}
<div class="contact-page">
<h1>{{ .Title }}</h1>
<form action="https://kollect.app/f/YOUR_FORM_KEY" method="POST" class="contact-form">
<div class="form-group">
<label for="name">Name</label>
<input type="text" id="name" name="name" required>
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" id="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>
</div>
{{ end }}Using Shortcodes
Create a reusable contact form shortcode:
<!-- layouts/shortcodes/contact-form.html -->
<form action="https://kollect.app/f/{{ .Get "key" }}" method="POST" class="kollect-form">
<div class="form-group">
<label for="name">Name</label>
<input type="text" id="name" name="name" required>
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" id="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">{{ .Get "submit" | default "Submit" }}</button>
</form>Use in your content:
<!-- content/contact.md -->
---
title: Contact Us
---
## Get in Touch
{{< contact-form key="YOUR_FORM_KEY" submit="Send Message" >}}Newsletter Signup Shortcode
<!-- layouts/shortcodes/newsletter.html -->
<div class="newsletter-signup">
<form action="https://kollect.app/f/{{ .Get "key" }}" method="POST" class="newsletter-form">
<input
type="email"
name="email"
placeholder="{{ .Get "placeholder" | default "Enter your email" }}"
required
>
<button type="submit">{{ .Get "submit" | default "Subscribe" }}</button>
</form>
</div>Use in templates or content:
{{ with .Site.Params.newsletterFormKey }}
{{< newsletter key=. submit="Subscribe" placeholder="Your email address" >}}
{{ end }}Configuration with Config File
Store form keys in your configuration:
# config.toml
[params]
contactFormKey = "your_contact_form_key"
newsletterFormKey = "your_newsletter_form_key"Or in YAML:
# config.yaml
params:
contactFormKey: "your_contact_form_key"
newsletterFormKey: "your_newsletter_form_key"Use in templates:
<form action="https://kollect.app/f/{{ .Site.Params.contactFormKey }}" method="POST">
<!-- form fields -->
</form>Advanced Form with Validation
<!-- layouts/partials/advanced-form.html -->
<form
action="https://kollect.app/f/{{ .Site.Params.contactFormKey }}"
method="POST"
id="contact-form"
class="contact-form"
>
<div class="form-group">
<label for="name">Name *</label>
<input
type="text"
id="name"
name="name"
required
minlength="2"
>
<span class="error-message" data-error="name"></span>
</div>
<div class="form-group">
<label for="email">Email *</label>
<input
type="email"
id="email"
name="email"
required
>
<span class="error-message" data-error="email"></span>
</div>
<div class="form-group">
<label for="phone">Phone</label>
<input
type="tel"
id="phone"
name="phone"
pattern="[0-9]{10}"
>
<span class="error-message" data-error="phone"></span>
</div>
<div class="form-group">
<label for="subject">Subject *</label>
<select id="subject" name="subject" required>
<option value="">Choose a subject</option>
<option value="general">General Inquiry</option>
<option value="support">Support</option>
<option value="sales">Sales</option>
</select>
</div>
<div class="form-group">
<label for="message">Message *</label>
<textarea
id="message"
name="message"
rows="5"
required
minlength="10"
></textarea>
<span class="error-message" data-error="message"></span>
</div>
<button type="submit" id="submit-btn">
<span class="btn-text">Send Message</span>
<span class="btn-loading" style="display: none;">Sending...</span>
</button>
<div id="form-status" style="display: none;"></div>
</form>
<script>
document.getElementById('contact-form').addEventListener('submit', async function(e) {
e.preventDefault();
const form = e.target;
const submitBtn = document.getElementById('submit-btn');
const btnText = submitBtn.querySelector('.btn-text');
const btnLoading = submitBtn.querySelector('.btn-loading');
const statusDiv = document.getElementById('form-status');
// Disable submit button
submitBtn.disabled = true;
btnText.style.display = 'none';
btnLoading.style.display = 'inline';
try {
const response = await fetch(form.action, {
method: 'POST',
body: new FormData(form)
});
if (response.ok) {
statusDiv.textContent = 'Thank you! Your message has been sent.';
statusDiv.className = 'success-message';
statusDiv.style.display = 'block';
form.reset();
} else {
throw new Error('Submission failed');
}
} catch (error) {
statusDiv.textContent = 'Oops! Something went wrong. Please try again.';
statusDiv.className = 'error-message';
statusDiv.style.display = 'block';
} finally {
submitBtn.disabled = false;
btnText.style.display = 'inline';
btnLoading.style.display = 'none';
}
});
</script>File Upload Form
<!-- layouts/partials/file-upload-form.html -->
<form
action="https://kollect.app/f/{{ .Site.Params.uploadFormKey }}"
method="POST"
enctype="multipart/form-data"
>
<div class="form-group">
<label for="name">Name</label>
<input type="text" id="name" name="name" required>
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" id="email" name="email" required>
</div>
<div class="form-group">
<label for="resume">Resume (PDF only)</label>
<input
type="file"
id="resume"
name="resume"
accept=".pdf"
required
>
<small>Maximum file size: 10MB</small>
</div>
<button type="submit">Submit Application</button>
</form>Multi-Step Form
<!-- layouts/partials/multi-step-form.html -->
<div class="multi-step-form">
<div class="progress-bar">
<div class="step active" data-step="1">1. Personal Info</div>
<div class="step" data-step="2">2. Details</div>
<div class="step" data-step="3">3. Review</div>
</div>
<form action="https://kollect.app/f/{{ .Site.Params.contactFormKey }}" method="POST" id="multi-step-form">
<!-- Step 1 -->
<div class="form-step active" data-step="1">
<h3>Personal Information</h3>
<div class="form-group">
<label for="firstName">First Name</label>
<input type="text" id="firstName" name="firstName" required>
</div>
<div class="form-group">
<label for="lastName">Last Name</label>
<input type="text" id="lastName" name="lastName" required>
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" id="email" name="email" required>
</div>
<button type="button" class="next-btn" data-next="2">Next</button>
</div>
<!-- Step 2 -->
<div class="form-step" data-step="2">
<h3>Additional Details</h3>
<div class="form-group">
<label for="company">Company</label>
<input type="text" id="company" name="company">
</div>
<div class="form-group">
<label for="message">Message</label>
<textarea id="message" name="message" rows="5"></textarea>
</div>
<button type="button" class="prev-btn" data-prev="1">Previous</button>
<button type="button" class="next-btn" data-next="3">Next</button>
</div>
<!-- Step 3 -->
<div class="form-step" data-step="3">
<h3>Review & Submit</h3>
<div id="review-content"></div>
<button type="button" class="prev-btn" data-prev="2">Previous</button>
<button type="submit">Submit</button>
</div>
</form>
</div>
<script src="/js/multi-step-form.js"></script>Styling
Add to your stylesheet:
/* assets/css/forms.css */
.contact-form {
max-width: 600px;
margin: 0 auto;
}
.form-group {
margin-bottom: 1.5rem;
}
.form-group label {
display: block;
margin-bottom: 0.5rem;
font-weight: 500;
}
.form-group input,
.form-group textarea,
.form-group select {
width: 100%;
padding: 0.75rem;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 1rem;
}
.form-group input:focus,
.form-group textarea:focus,
.form-group select:focus {
outline: none;
border-color: #8B5CF6;
box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.1);
}
button[type="submit"] {
padding: 0.75rem 2rem;
background: #8B5CF6;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 1rem;
transition: background 0.2s;
}
button[type="submit"]:hover {
background: #7C3AED;
}
button[type="submit"]:disabled {
background: #ccc;
cursor: not-allowed;
}
.success-message {
padding: 1rem;
background: #d4edda;
border: 1px solid #c3e6cb;
border-radius: 4px;
color: #155724;
margin-top: 1rem;
}
.error-message {
padding: 1rem;
background: #f8d7da;
border: 1px solid #f5c6cb;
border-radius: 4px;
color: #721c24;
margin-top: 1rem;
}Environment-Specific Keys
Use different form keys for development and production:
# config/_default/params.toml
[forms]
contact = "dev_form_key"
# config/production/params.toml
[forms]
contact = "prod_form_key"Integration with Hugo Pipes
Process forms with Hugo’s asset pipeline:
{{ $formJS := resources.Get "js/form-handler.js" | minify | fingerprint }}
<script src="{{ $formJS.RelPermalink }}" integrity="{{ $formJS.Data.Integrity }}"></script>Next Steps
Last updated on