NextJS returning 404 on form submission

Hello!

I’m currently having issues with form submissions on all my sites nextjs sites. Every time I try to submit a form, it’s returning a 404 saying that it can’t find the html file in the public folder where the form posts to. I’ve never had this issue in the past up until recently, and I’m struggling to understand why it’s giving me a 404 message. I’ve tried various solutions on the forums, but I can’t find anything that is solving the issue. If anyone could please give some advice, I would greatly appreciate it. Below is the code:

contact-form.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>hidden form</title>
  </head>
  <body>
    <form name="Contact" netlify netlify-honeypot="bot-field" hidden>
      <input type="hidden" name="Contact" value="Contact" />
      <input type="text" name="first-name" />
      <input type="text" name="last-name" />
      <input type="email" name="email" />
      <input type="text" name="phone-number" />
      <textarea name="message"></textarea>
    </form>
  </body>
</html>

The contact page:

"use client";
import Footer from "../components/footer";
import Navbar from "../components/nav";

export default function Contact() {
  function handleSubmit(e) {
    e.preventDefault();

    let newForm = document.querySelector("form");
    let formData = new FormData(newForm);

    fetch("/contact-form.html", {
      method: "POST",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      body: new URLSearchParams(formData).toString(),
    })
      .then(() => console.log("success"))
      .catch((error) => alert(error));
  }

  return (
    <div
      className="relative bg-foreground"
      style={{
        backgroundImage: `url("/images/bodybg.webp")`,
      }}
    >
      <Navbar />
      <div className="lg:absolute lg:inset-0 lg:left-1/2">
        <img
          className="h-64 w-full bg-gray-50 object-cover sm:h-80 lg:absolute lg:h-full"
          src="/images/contact.webp"
          alt=""
        />
      </div>
      <div className="pb-24 pt-16 sm:pb-32 sm:pt-24 lg:mx-auto lg:grid lg:max-w-7xl lg:grid-cols-2 lg:pt-32">
        <div className="px-6 lg:px-8">
          <div className="mx-auto max-w-xl lg:mx-0 lg:max-w-lg">
            <h2 className="text-3xl font-bold tracking-tight text-text">
              Drop Us a Line!
            </h2>
            <p className="mt-2 text-lg leading-8 text-gray-800">
              We&apos;d love to hear from you! Fill out the form below to send
              us a message.
            </p>
            <form
              method="POST"
              className="mt-16"
              data-netlify="true"
              actions="/contact-form.html"
              onSubmit={handleSubmit}
            >
              <input type="hidden" name="Contact" value="Contact" />
              <div className="grid grid-cols-1 gap-x-8 gap-y-6 sm:grid-cols-2">
                <div>
                  <label
                    htmlFor="first-name"
                    name="first-name"
                    className="block text-base leading-6 text-text font-bold"
                  >
                    First name
                  </label>
                  <div className="mt-2.5">
                    <input
                      type="text"
                      name="first-name"
                      id="first-name"
                      autoComplete="given-name"
                      className="block w-full rounded-md border-0 px-3.5 py-2 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                    />
                  </div>
                </div>
                <div>
                  <label
                    htmlFor="last-name"
                    name="last-name"
                    className="block text-base leading-6 text-text font-bold"
                  >
                    Last name
                  </label>
                  <div className="mt-2.5">
                    <input
                      type="text"
                      name="last-name"
                      id="last-name"
                      autoComplete="family-name"
                      className="block w-full rounded-md border-0 px-3.5 py-2 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                    />
                  </div>
                </div>
                <div className="sm:col-span-2">
                  <label
                    htmlFor="email"
                    name="email"
                    className="block text-base leading-6 text-text font-bold"
                  >
                    Email
                  </label>
                  <div className="mt-2.5">
                    <input
                      id="email"
                      name="email"
                      type="email"
                      autoComplete="email"
                      className="block w-full rounded-md border-0 px-3.5 py-2 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                    />
                  </div>
                </div>
                <div className="sm:col-span-2">
                  <div className="flex justify-between text-sm leading-6">
                    <label
                      htmlFor="phone-number"
                      name="phone-number"
                      className="block text-base leading-6 text-text font-bold"
                    >
                      Phone
                    </label>
                    <p id="phone-description" className="text-gray-500">
                      Optional
                    </p>
                  </div>
                  <div className="mt-2.5">
                    <input
                      type="tel"
                      name="phone"
                      id="phone"
                      autoComplete="tel"
                      aria-describedby="phone-description"
                      className="block w-full rounded-md border-0 px-3.5 py-2 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                    />
                  </div>
                </div>
                <div className="sm:col-span-2">
                  <div className="flex justify-between text-sm leading-6">
                    <label
                      htmlFor="message"
                      name="message"
                      className="block text-base leading-6 text-text font-bold"
                    >
                      How can we help you?
                    </label>
                    <p id="message-description" className="text-gray-500">
                      Max 500 characters
                    </p>
                  </div>
                  <div className="mt-2.5">
                    <textarea
                      id="message"
                      name="message"
                      rows={4}
                      aria-describedby="message-description"
                      className="block w-full rounded-md border-0 px-3.5 py-2 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                      defaultValue={""}
                    />
                  </div>
                </div>
              </div>
              <div className="mt-10 flex justify-end border-t border-gray-900/10 pt-8">
                <button
                  type="submit"
                  className="w-full rounded-md bg-primary px-4.5 py-3.5 text-center text-sm font-semibold text-white shadow-sm transition-all duration-200 hover:bg-accent hover:text-text"
                >
                  Send message
                </button>
              </div>
            </form>
          </div>
        </div>
      </div>
      <div className="relative z-50">
        <Footer />
      </div>
    </div>
  );
}

Again, thank you very much for any help and any guidance that you all can give.

Mind providing a link to the form?

Sure, here it is: Contact Us | Pale Black Dot

I’ve tried following the example here: next-platform-starter/components/feedback-form.jsx at main · netlify-templates/next-platform-starter · GitHub

After utilizing that example, I’m still receiving a 404 error. The only time I didn’t receive that error was when I changed the fetch to the actual form itself from:

fetch('/contact-form.html')

to

fetch('/')

However, Netlify didn’t collect any form submission data.

Thank you for your help!

You seem to be making a request to https://paleblackdotllc.com/api/contact. Did something change?

I had the same problem and solved it using the following codes:

// Convert FormData to an object (Record<string, string>)
const formObject: Record<string, string> = {};
formData.forEach((value, key) => {
  formObject[key] = value.toString(); // Ensure that values are strings
});


const res = await fetch('/__forms.html', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams(formObject).toString()
});

I guess the error is caused by the formData being in wrong data format.