Skip to Content
ExamplesGatsby Integration

Gatsby Integration

Integrating Kollect with Gatsby is straightforward. This guide shows you how to add forms to your Gatsby site.

Basic Setup

1. Create a Contact Form Component

// src/components/ContactForm.jsx import React from 'react'; const ContactForm = () => { return ( <form action="https://kollect.app/f/YOUR_FORM_KEY" method="POST" style={{ maxWidth: '500px', margin: '0 auto' }} > <div style={{ marginBottom: '1rem' }}> <label htmlFor="name" style={{ display: 'block', marginBottom: '0.5rem' }}> Name </label> <input type="text" id="name" name="name" required style={{ width: '100%', padding: '0.5rem', borderRadius: '4px', border: '1px solid #ccc' }} /> </div> <div style={{ marginBottom: '1rem' }}> <label htmlFor="email" style={{ display: 'block', marginBottom: '0.5rem' }}> Email </label> <input type="email" id="email" name="email" required style={{ width: '100%', padding: '0.5rem', borderRadius: '4px', border: '1px solid #ccc' }} /> </div> <div style={{ marginBottom: '1rem' }}> <label htmlFor="message" style={{ display: 'block', marginBottom: '0.5rem' }}> Message </label> <textarea id="message" name="message" rows="5" required style={{ width: '100%', padding: '0.5rem', borderRadius: '4px', border: '1px solid #ccc' }} /> </div> <button type="submit" style={{ padding: '0.75rem 2rem', background: '#8B5CF6', color: 'white', border: 'none', borderRadius: '4px', cursor: 'pointer', fontSize: '1rem' }} > Send Message </button> </form> ); }; export default ContactForm;

2. Use the Component in a Page

// src/pages/contact.jsx import React from 'react'; import Layout from '../components/Layout'; import ContactForm from '../components/ContactForm'; const ContactPage = () => { return ( <Layout> <h1>Contact Us</h1> <p>We'd love to hear from you!</p> <ContactForm /> </Layout> ); }; export default ContactPage;

AJAX Submission with State

For a better user experience, handle the submission with JavaScript:

// src/components/ContactFormAjax.jsx import React, { useState } from 'react'; const ContactFormAjax = () => { const [status, setStatus] = useState('idle'); // idle, submitting, success, error const [message, setMessage] = useState(''); const handleSubmit = async (e) => { e.preventDefault(); setStatus('submitting'); const formData = new FormData(e.target); try { const response = await fetch('https://kollect.app/f/YOUR_FORM_KEY', { method: 'POST', body: formData, }); if (response.ok) { setStatus('success'); setMessage('Thank you! Your message has been sent.'); e.target.reset(); } else { throw new Error('Form submission failed'); } } catch (error) { setStatus('error'); setMessage('Oops! Something went wrong. Please try again.'); } }; return ( <div> <form onSubmit={handleSubmit} style={{ maxWidth: '500px', margin: '0 auto' }}> <div style={{ marginBottom: '1rem' }}> <label htmlFor="name">Name</label> <input type="text" id="name" name="name" required /> </div> <div style={{ marginBottom: '1rem' }}> <label htmlFor="email">Email</label> <input type="email" id="email" name="email" required /> </div> <div style={{ marginBottom: '1rem' }}> <label htmlFor="message">Message</label> <textarea id="message" name="message" rows="5" required /> </div> <button type="submit" disabled={status === 'submitting'}> {status === 'submitting' ? 'Sending...' : 'Send Message'} </button> </form> {status === 'success' && ( <div style={{ marginTop: '1rem', padding: '1rem', background: '#d4edda', borderRadius: '4px' }}> {message} </div> )} {status === 'error' && ( <div style={{ marginTop: '1rem', padding: '1rem', background: '#f8d7da', borderRadius: '4px' }}> {message} </div> )} </div> ); }; export default ContactFormAjax;

File Uploads

// src/components/FileUploadForm.jsx import React from 'react'; const FileUploadForm = () => { return ( <form action="https://kollect.app/f/YOUR_FORM_KEY" method="POST" encType="multipart/form-data" > <div> <label htmlFor="name">Name</label> <input type="text" id="name" name="name" required /> </div> <div> <label htmlFor="resume">Upload Resume (PDF)</label> <input type="file" id="resume" name="resume" accept=".pdf" required /> </div> <button type="submit">Submit Application</button> </form> ); }; export default FileUploadForm;

Newsletter Signup

// src/components/NewsletterForm.jsx import React, { useState } from 'react'; const NewsletterForm = () => { const [email, setEmail] = useState(''); const [status, setStatus] = useState('idle'); const handleSubmit = async (e) => { e.preventDefault(); setStatus('submitting'); const formData = new FormData(); formData.append('email', email); try { await fetch('https://kollect.app/f/YOUR_FORM_KEY', { method: 'POST', body: formData, }); setStatus('success'); setEmail(''); } catch (error) { setStatus('error'); } }; return ( <form onSubmit={handleSubmit} style={{ display: 'flex', gap: '1rem' }}> <input type="email" placeholder="Enter your email" value={email} onChange={(e) => setEmail(e.target.value)} required style={{ flex: 1, padding: '0.5rem' }} /> <button type="submit" disabled={status === 'submitting'}> {status === 'submitting' ? 'Subscribing...' : 'Subscribe'} </button> {status === 'success' && <span>✓ Subscribed!</span>} {status === 'error' && <span>✗ Error</span>} </form> ); }; export default NewsletterForm;

Using with Gatsby Plugins

If you’re using styled-components or Emotion:

// src/components/StyledContactForm.jsx import React from 'react'; import styled from 'styled-components'; const FormContainer = styled.form` max-width: 500px; margin: 0 auto; `; const FormGroup = styled.div` margin-bottom: 1rem; `; const Label = styled.label` display: block; margin-bottom: 0.5rem; font-weight: 500; `; const Input = styled.input` width: 100%; padding: 0.75rem; border: 1px solid #ccc; border-radius: 4px; font-size: 1rem; `; const TextArea = styled.textarea` width: 100%; padding: 0.75rem; border: 1px solid #ccc; border-radius: 4px; font-size: 1rem; `; const SubmitButton = styled.button` padding: 0.75rem 2rem; background: #8B5CF6; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 1rem; transition: background 0.2s; &:hover { background: #7C3AED; } `; const StyledContactForm = () => { return ( <FormContainer action="https://kollect.app/f/YOUR_FORM_KEY" method="POST"> <FormGroup> <Label htmlFor="name">Name</Label> <Input type="text" id="name" name="name" required /> </FormGroup> <FormGroup> <Label htmlFor="email">Email</Label> <Input type="email" id="email" name="email" required /> </FormGroup> <FormGroup> <Label htmlFor="message">Message</Label> <TextArea id="message" name="message" rows="5" required /> </FormGroup> <SubmitButton type="submit">Send Message</SubmitButton> </FormContainer> ); }; export default StyledContactForm;

Environment Variables

Store your form key in environment variables:

# .env.development GATSBY_KOLLECT_FORM_KEY=your_development_key # .env.production GATSBY_KOLLECT_FORM_KEY=your_production_key

Use in your component:

const ContactForm = () => { const formEndpoint = `https://kollect.app/f/${process.env.GATSBY_KOLLECT_FORM_KEY}`; return ( <form action={formEndpoint} method="POST"> {/* form fields */} </form> ); };

TypeScript Support

// src/components/ContactForm.tsx import React, { FormEvent, useState } from 'react'; interface FormData { name: string; email: string; message: string; } const ContactForm: React.FC = () => { const [formData, setFormData] = useState<FormData>({ name: '', email: '', message: '', }); const [status, setStatus] = useState<'idle' | 'submitting' | 'success' | 'error'>('idle'); const handleSubmit = async (e: FormEvent<HTMLFormElement>) => { e.preventDefault(); setStatus('submitting'); const data = new FormData(); Object.entries(formData).forEach(([key, value]) => { data.append(key, value); }); try { const response = await fetch('https://kollect.app/f/YOUR_FORM_KEY', { method: 'POST', body: data, }); if (response.ok) { setStatus('success'); setFormData({ name: '', email: '', message: '' }); } else { setStatus('error'); } } catch (error) { setStatus('error'); } }; return ( <form onSubmit={handleSubmit}> {/* form implementation */} </form> ); }; export default ContactForm;

Next Steps

Last updated on