Skip to main content

Basic Form Component

Create a contact form component:
src/components/ContactForm.jsx
import React, { useState } from "react";

export default function ContactForm({ formSlug }) {
  const [status, setStatus] = useState("idle");
  
  const handleSubmit = async (e) => {
    e.preventDefault();
    setStatus("loading");
    
    const data = new FormData(e.target);
    
    const res = await fetch(`https://spike.ac/api/f/${formSlug}`, {
      method: "POST",
      body: data,
      headers: { Accept: "application/json" },
    });
    
    setStatus(res.ok ? "success" : "error");
    if (res.ok) e.target.reset();
  };
  
  return (
    <form onSubmit={handleSubmit}>
      <input type="text" name="_gotcha" style={{ display: "none" }} />
      
      <input type="text" name="name" placeholder="Name" required />
      <input type="email" name="email" placeholder="Email" required />
      <textarea name="message" placeholder="Message" required />
      
      <button disabled={status === "loading"}>
        {status === "loading" ? "Sending..." : "Send"}
      </button>
      
      {status === "success" && <p>Thanks!</p>}
      {status === "error" && <p>Error, please try again.</p>}
    </form>
  );
}

Usage

src/pages/contact.js
import React from "react";
import ContactForm from "../components/ContactForm";

export default function ContactPage() {
  return (
    <div>
      <h1>Contact Us</h1>
      <ContactForm formSlug="YOUR_FORM_SLUG" />
    </div>
  );
}

TypeScript Version

src/components/ContactForm.tsx
import React, { useState, FormEvent } from "react";

interface ContactFormProps {
  formSlug: string;
}

type Status = "idle" | "loading" | "success" | "error";

export default function ContactForm({ formSlug }: ContactFormProps) {
  const [status, setStatus] = useState<Status>("idle");
  
  const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    setStatus("loading");
    
    const form = e.currentTarget;
    const data = new FormData(form);
    
    try {
      const res = await fetch(`https://spike.ac/api/f/${formSlug}`, {
        method: "POST",
        body: data,
        headers: { Accept: "application/json" },
      });
      
      setStatus(res.ok ? "success" : "error");
      if (res.ok) form.reset();
    } catch {
      setStatus("error");
    }
  };
  
  return (
    <form onSubmit={handleSubmit}>
      <input type="text" name="_gotcha" style={{ display: "none" }} />
      
      <input type="text" name="name" placeholder="Name" required />
      <input type="email" name="email" placeholder="Email" required />
      <textarea name="message" placeholder="Message" required />
      
      <button type="submit" disabled={status === "loading"}>
        {status === "loading" ? "Sending..." : "Send"}
      </button>
      
      {status === "success" && <p>Thanks!</p>}
      {status === "error" && <p>Error, please try again.</p>}
    </form>
  );
}

Simple HTML Form

For basic use without JavaScript:
<form action="https://spike.ac/api/f/YOUR_FORM_SLUG" method="POST">
  <input type="hidden" name="_next" value="/thanks/" />
  <input type="text" name="_gotcha" style="display:none" />
  
  <input type="text" name="name" required />
  <input type="email" name="email" required />
  <textarea name="message" required></textarea>
  
  <button type="submit">Send</button>
</form>