Hidden form fields not showing in submission and notification

Contact from here is a netlify form. I have a bunch of hidden fields that I’m using for utm param values. They’re not showing in the submission in netlify and the email notification. Tried using a different form name, that didn’t work. Tried hidden fields, text fields in display: none divs – didn’t work either. I can see the values being sent with the request. What am I missing?

import React, { useState, useEffect } from "react"
import { getStoredParams, getLastReferrer } from "../../helpers/paramUtils";

export default function ContactForm({ block }) {
  useEffect(() => {
    const storedParams = getStoredParams();
    const currentReferrer = getLastReferrer();
    if (storedParams) {
      document.getElementById('utm_source').value = storedParams.utm_source || '';
      document.getElementById('utm_campaign').value = storedParams.utm_campaign || '';
      document.getElementById('utm_medium').value = storedParams.utm_medium || '';
      document.getElementById('utm_content').value = storedParams.utm_content || '';
      document.getElementById('fbclid').value = storedParams.fbclid || '';
      document.getElementById('gclid').value = storedParams.gclid || '';
      document.getElementById('referrer').value = currentReferrer || '';
    }
  }, []);
  
  const { heading } = block;
  
  const [isLoading, setIsLoading] = useState(false)
  const [isSuccess, setIsSuccess] = useState(false)
  const [isError, setIsError] = useState(false)
  
  const handleSubmit = async (event) => {
    event.preventDefault();
  
    const myForm = event.target;
    const formData = new FormData(myForm);
    
    try {
        setIsError(false)
        setIsLoading(true)
        fetch("/favicon.ico", {
          method: "POST",
          headers: { "Content-Type": "application/x-www-form-urlencoded" },
          body: new URLSearchParams(formData).toString(),
        })
          .then(() => {
            setIsLoading(false)
            setIsSuccess(true)
            window.dataLayer = window.dataLayer || []
            window.dataLayer.push({
              event: 'tba.form.confirmation',
              eventData: {
                formTitle: 'Contact Us', 
                formLocation: 'contact'
              }
            })
          })
          .catch((error) => {
            setIsLoading(false)
            setIsSuccess(false)
            setIsError(true)
          });
      } catch (error) {
        setIsLoading(false)
        setIsError(true)
    }
  };
    
  return (
    <>
    <div id="form" className="-top-32 relative"></div>
    <div className="container container--constrained relative">
      {isError && (
        <div className="alert alert-danger form-error">
          Sorry, an unexpected error occurred. Please try again.
        </div>
      )}
      {isSuccess ? (
        <div className="alert alert-success form-success" style={{ 'text-align': 'center' }}>
          Thank you for your submission. We'll be in touch soon!
        </div>
      ) : (
        <form
          className="my-12 md:my-24"
          name="contact"
          action="/success"
          method="POST"
          data-netlify="true"
          onSubmit={e => handleSubmit(e)}
        >
          <input type="hidden" name="form-name" value="contact" />
          <div className="mt-6 grid grid-cols-1 gap-y-6 gap-x-4 sm:grid-cols-6">
            <div style={{ display: 'none' }}>
              <label htmlFor="utm_source">UTM Source</label>
              <input type="text" name="utm_source" id="utm_source"/>
            </div>
            <div style={{ display: 'none' }}>
              <label htmlFor="utm_campaign">UTM Campaign</label>
              <input type="text" name="utm_campaign" id="utm_campaign"/>
            </div>
            <div style={{ display: 'none' }}>
              <label htmlFor="utm_medium">UTM Medium</label>
              <input type="text" name="utm_medium" id="utm_medium"/>
            </div>
            <div style={{ display: 'none' }}>
              <label htmlFor="utm_content">UTM Content</label>
              <input type="text" name="utm_content" id="utm_content"/>
            </div>
            <div style={{ display: 'none' }}>
              <label htmlFor="fbclid">FB clid</label>
              <input type="text" name="fbclid" id="fbclid"/>
            </div>
            <div style={{ display: 'none' }}>
              <label htmlFor="gclid">G clid</label>
              <input type="text" name="gclid" id="gclid"/>
            </div>
            <div style={{ display: 'none' }}>
              <label htmlFor="referrer">Referrer</label>
              <input type="text" name="referrer" id="referrer"/>
            </div>
            <div className="sm:col-span-3">
              <label
                htmlFor="first-name"
                className="block font-medium text-gray-700"
              >
                First Name <em className="text-teal-500">(Required)</em>
              </label>
              <div className="mt-1">
                <input
                  type="text"
                  name="first-name"
                  id="first-name"
                  autoComplete="given-name"
                  className="block w-full rounded-md border-gray-300 shadow-sm focus:border-teal-500 focus:ring-teal-500"
                  required
                />
              </div>
            </div>
  
            <div className="sm:col-span-3">
              <label
                htmlFor="last-name"
                className="block font-medium text-gray-700"
              >
                Last Name <em className="text-teal-500">(Required)</em>
              </label>
              <div className="mt-1">
                <input
                  type="text"
                  name="last-name"
                  id="last-name"
                  autoComplete="family-name"
                  className="block w-full rounded-md border-gray-300 shadow-sm focus:border-teal-500 focus:ring-teal-500"
                  required
                />
              </div>
            </div>
  
            <div className="sm:col-span-3">
              <label htmlFor="email" className="block font-medium text-gray-700">
                Email <em className="text-teal-500">(Required)</em>
              </label>
              <div className="mt-1">
                <input
                  id="email"
                  name="email"
                  type="email"
                  autoComplete="email"
                  className="block w-full rounded-md border-gray-300 shadow-sm focus:border-teal-500 focus:ring-teal-500"
                  required
                />
              </div>
            </div>
  
            <div className="sm:col-span-3">
              <label htmlFor="phone" className="block font-medium text-gray-700">
                Phone <em className="text-teal-500">(Required)</em>
              </label>
              <div className="mt-1">
                <input
                  id="phone"
                  name="phone"
                  type="text"
                  autoComplete="phone"
                  className="block w-full rounded-md border-gray-300 shadow-sm focus:border-teal-500 focus:ring-teal-500"
                  required
                />
              </div>
            </div>
  
            <div className="sm:col-span-6">
              <label
                htmlFor="message"
                className="block font-medium text-gray-700"
              >
                Message <em className="text-teal-500">(Required)</em>
              </label>
              <div className="mt-1">
                <textarea
                  id="message"
                  name="message"
                  type="text"
                  rows="10"
                  className="block w-full rounded-md border-gray-300 shadow-sm focus:border-teal-500 focus:ring-teal-500"
                  required
                />
              </div>
            </div>
  
            <div className="sm:col-span-6">
              <button type="submit" className="button">
                Submit
              </button>
            </div>
            
            {isLoading && (
              <div className="loading-rings">
                <div></div>
                <div></div>
                <div></div>
                <div></div>
              </div>
            )}
          </div>
        </form>
      )}
    </div>
    </>
  );
}

Hi, @dev14. This is the starting place for debugging forms issues:

Would you please read that support guide and let us know if it helps or not?

Hi Luke,

I read that post and tried everything from it before posting. I even tried adding an additional visible standard text field to the form and it didn’t show in the submission or notification. I see the values in the post request, I see the submission, I receive the notification, but only the original field values are there.

Here’s the latest:

import React, { useState, useEffect } from "react"
import { getStoredParams, getLastReferrer } from "../../helpers/paramUtils";

export default function ContactForm({ block }) {

  const [utmSource, setUtmSource] = useState('')
  const [utmCampaign, setUtmCampaign] = useState('')
  const [utmMedium, setUtmMedium] = useState('')
  const [utmContent, setUtmContent] = useState('')
  const [fbclid, setFbclid] = useState('')
  const [gclid, setGclid] = useState('')
  const [referrer, setReferrer] = useState('')


  useEffect(() => {
    const storedParams = getStoredParams();
    const currentReferrer = getLastReferrer();
    if (storedParams) {
      setUtmSource(storedParams.utm_source || '');
      setUtmCampaign(storedParams.utm_campaign || '');
      setUtmContent(storedParams.utm_content || '');
      setUtmMedium(storedParams.utm_medium || '');
      setFbclid(storedParams.fbclid || '');
      setGclid(storedParams.gclid || '');
      setReferrer(currentReferrer || '');
    }
  }, []);
  
  const { heading } = block;
  
  const [isLoading, setIsLoading] = useState(false)
  const [isSuccess, setIsSuccess] = useState(false)
  const [isError, setIsError] = useState(false)
  
  const handleSubmit = async (event) => {
    event.preventDefault();
  
    const myForm = event.target;
    const formData = new FormData(myForm);
    
    try {
        setIsError(false)
        setIsLoading(true)
        fetch("/favicon.ico", {
          method: "POST",
          headers: { "Content-Type": "application/x-www-form-urlencoded" },
          body: new URLSearchParams(formData).toString(),
        })
          .then(() => {
            setIsLoading(false)
            setIsSuccess(true)
            window.dataLayer = window.dataLayer || []
            window.dataLayer.push({
              event: 'tba.form.confirmation',
              eventData: {
                formTitle: 'Contact Us', 
                formLocation: 'contact'
              }
            })
          })
          .catch((error) => {
            setIsLoading(false)
            setIsSuccess(false)
            setIsError(true)
          });
      } catch (error) {
        setIsLoading(false)
        setIsError(true)
    }
  };
    
  return (
    <>
    <div id="form" className="-top-32 relative"></div>
    <div className="container container--constrained relative">
      {isError && (
        <div className="alert alert-danger form-error">
          Sorry, an unexpected error occurred. Please try again.
        </div>
      )}
      {isSuccess ? (
        <div className="alert alert-success form-success" style={{ 'text-align': 'center' }}>
          Thank you for your submission. We'll be in touch soon!
        </div>
      ) : (
        <form
          className="my-12 md:my-24"
          name="contact"
          action="/success"
          method="POST"
          data-netlify="true"
          onSubmit={e => handleSubmit(e)}
        >
          <input type="hidden" name="form-name" value="contact" />
          <div className="mt-6 grid grid-cols-1 gap-y-6 gap-x-4 sm:grid-cols-6">
            <div className="sm:col-span-3">
              <label
                htmlFor="first-name"
                className="block font-medium text-gray-700"
              >
                First Name <em className="text-teal-500">(Required)</em>
              </label>
              <div className="mt-1">
                <input
                  type="text"
                  name="first-name"
                  id="first-name"
                  autoComplete="given-name"
                  className="block w-full rounded-md border-gray-300 shadow-sm focus:border-teal-500 focus:ring-teal-500"
                  required
                />
              </div>
            </div>
  
            <div className="sm:col-span-3">
              <label
                htmlFor="last-name"
                className="block font-medium text-gray-700"
              >
                Last Name <em className="text-teal-500">(Required)</em>
              </label>
              <div className="mt-1">
                <input
                  type="text"
                  name="last-name"
                  id="last-name"
                  autoComplete="family-name"
                  className="block w-full rounded-md border-gray-300 shadow-sm focus:border-teal-500 focus:ring-teal-500"
                  required
                />
              </div>
            </div>
  
            <div className="sm:col-span-3">
              <label htmlFor="email" className="block font-medium text-gray-700">
                Email <em className="text-teal-500">(Required)</em>
              </label>
              <div className="mt-1">
                <input
                  id="email"
                  name="email"
                  type="email"
                  autoComplete="email"
                  className="block w-full rounded-md border-gray-300 shadow-sm focus:border-teal-500 focus:ring-teal-500"
                  required
                />
              </div>
            </div>
  
            <div className="sm:col-span-3">
              <label htmlFor="phone" className="block font-medium text-gray-700">
                Phone <em className="text-teal-500">(Required)</em>
              </label>
              <div className="mt-1">
                <input
                  id="phone"
                  name="phone"
                  type="text"
                  autoComplete="phone"
                  className="block w-full rounded-md border-gray-300 shadow-sm focus:border-teal-500 focus:ring-teal-500"
                  required
                />
              </div>
            </div>
            
            <div className="sm:col-span-3">
              <label htmlFor="zip-code" className="block font-medium text-gray-700">
                Zip Code <em className="text-teal-500">(Required)</em>
              </label>
              <div className="mt-1">
                <input
                  id="zip-code"
                  name="zip-code"
                  type="text"
                  autoComplete="zip-code"
                  className="block w-full rounded-md border-gray-300 shadow-sm focus:border-teal-500 focus:ring-teal-500"
                  required
                />
              </div>
            </div>
  
            <div className="sm:col-span-6">
              <label
                htmlFor="message"
                className="block font-medium text-gray-700"
              >
                Message <em className="text-teal-500">(Required)</em>
              </label>
              <div className="mt-1">
                <textarea
                  id="message"
                  name="message"
                  type="text"
                  rows="10"
                  className="block w-full rounded-md border-gray-300 shadow-sm focus:border-teal-500 focus:ring-teal-500"
                  required
                />
              </div>
            </div>
            <input type="hidden" name="utm_source" id="utm_source" value={utmSource}/>
            <input type="hidden" name="utm_campaign" id="utm_campaign" value={utmCampaign}/>
            <input type="hidden" name="utm_medium" id="utm_medium" value={utmMedium}/>
            <input type="hidden" name="utm_content" id="utm_content" value={utmContent}/>
            <input type="hidden" name="fbclid" id="fbclid" value={fbclid}/>
            <input type="hidden" name="gclid" id="gclid" value={gclid}/>
            <input type="hidden" name="referrer" id="referrer"  value={referrer}/>
  
            <div className="sm:col-span-6">
              <button type="submit" className="button">
                Submit
              </button>
            </div>
            
            {isLoading && (
              <div className="loading-rings">
                <div></div>
                <div></div>
                <div></div>
                <div></div>
              </div>
            )}
          </div>
        </form>
      )}
    </div>
    </>
  );
}

Hi, @dev14. Are you sure you have a pure HTML-only form defined in a static HTML file? If so, I cannot find it and that is a prerequisite for creating (or on this case for updating) the backend form handler.

It looks like this URL below is rendered by a function (so there is no static HTML file to parse):

I say this based on the HTTP response header for that page:

< HTTP/2 200
< age: 696
< cache-control: public,max-age=0,must-revalidate
< content-encoding: gzip
< content-type: text/html; charset=utf-8
< date: Thu, 23 Nov 2023 02:57:29 GMT
< etag: "iul4q997juecc"
< server: Netlify
< strict-transport-security: max-age=31536000; includeSubDomains; preload
< x-nextjs-cache: REVALIDATED
< x-nf-render-mode: odb ttl=60
< x-nf-request-id: 01HFX1RVJGY7VGXMX8612VQ7E1
< x-powered-by: Next.js

That is an ISR route above and so no static HTML file exists for this page. (The HTML is generated by a javascript function so it isn’t static HTML.)

The solution for this is to manually copy/paste the HTML <form> definition the function generates and then to put that HTML into a new static HTML file that gets deployed with the site. You don’t need to use the static HTML file. You can even block access to that URL with redirect rules (if you want to). The key here is this:

  • there must be a static HTML file with the <form> definition in the publish directory for the site when the build process ends

It looks like for Next.js sites, that you can put that HTML file into the directory name “public” in the repo to automatically have it copied to the publish directory during the build process:

It doesn’t matter what the HTML file is named. It only matters that it exists and that the form is in it. Again, you never need the real live site to use that file. The only purpose for that static HTML file is so the build system will scan it and that <form> tag definition at the end of the deploy to create (or update in this case) the backend form handler.

If adding the <form> definition to a static HTML file doesn’t resolve the issue or if there are other questions, please let us know.

Hi Luke,

Next.js takes care of outputting static HTML, that’s why I never needed a separate file containing a static form. However I disabled revalidate/ISR for the contact page and it worked.

Thanks for pointing me in the right direction.

1 Like