Issue with Gatsby + Formik Multi-Step + Netlify Forms

Hi guys,

I am trying to send data from a multi-step form made with Formik, to Netlify forms.
The data coming from the first WizardStep (firstName, lastName, email) is coming through correcly, but the second WizardStep (cnpj) data never comes through to Netlify.

Weird thing is after the POST, I am logging the values with console.log(values); and the result object seems correct {email: "email@gmail.com", firstName: "First", lastName: "Last", cnpj: "999999999"} but cnpj field never comes through to Netflify.

Any ideas how to fix this?
Appreciate the help!

lead-form.js

import React, { useState } from "react";
import { ErrorMessage, Field, Form, Formik } from "formik";
import * as Yup from "yup";
import { Debug } from "./debug";
import styled from "styled-components";
import { Container } from "../global";
import { navigate } from 'gatsby';

const encode = (data) => {
  return Object.keys(data)
    .map(key => encodeURIComponent(key) + "=" + encodeURIComponent(data[key]))
    .join("&");
}

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

// Wizard is a single Formik instance whose children are each page of the
// multi-step form. The form is submitted on each forward transition (can only
// progress with valid input), whereas a backwards step is allowed with
// incomplete data. A snapshot of form state is used as initialValues after each
// transition. Each page has an optional submit handler, and the top-level
// submit is called when the final page is submitted.

const Wizard = ({ children, initialValues, onSubmit }) => {
  const [stepNumber, setStepNumber] = useState(0);
  const steps = React.Children.toArray(children);
  const [snapshot, setSnapshot] = useState(initialValues);

  const step = steps[stepNumber];
  const totalSteps = steps.length;
  const isLastStep = stepNumber === totalSteps - 1;

  const next = values => {
    setSnapshot(values);
    setStepNumber(Math.min(stepNumber + 1, totalSteps - 1));
  };

  const previous = values => {
    setSnapshot(values);
    setStepNumber(Math.max(stepNumber - 1, 0));
  };

  const handleSubmit = async (values, bag) => {
    if (step.props.onSubmit) {
      await step.props.onSubmit(values, bag);
    }
    if (isLastStep) {
      return onSubmit(values, bag);
    } else {
      bag.setTouched({});
      next(values);
    }
  };

  return (
    <Container>
    <Formik
      initialValues={snapshot}
      onSubmit={handleSubmit}
      validationSchema={step.props.validationSchema}
    >

      {formik => (
        <Form
        bot-field = ""
        name="lead-form"
        data-netlify="true"
        data-netlify-honeypot="bot-field">
        <input type="hidden" name="form-name" value="lead-form" />
        <input type="hidden" name="bot-field" />
          <p>
            Step {stepNumber + 1} of {totalSteps}
          </p>
          {step}
          <div style={{ display: "flex" }}>
            {stepNumber > 0 && (
              <BackBtn onClick={() => previous(formik.values)} type="button"> 
                Voltar
              </BackBtn>
            )}
            <div>
              <NextBtn disabled={formik.isSubmitting} type="submit">
                {isLastStep ? "Enviar" : "Avançar"}
              </NextBtn>
            </div>
          </div>
          <Debug />
        </Form>
      )}
    </Formik>
    </Container>

  );
};

const WizardStep = ({ children }) => children;

const App = () => (
  <Container>

    <FieldSet>
    <Wizard
      initialValues={{
        email: "",
        firstName: "",
        lastName: "",
        cnpj: ""
      }}
      onSubmit={async values => {
        sleep(300).then(() => {
          fetch("/", {
            method: "POST",
            headers: { "Content-Type": "application/x-www-form-urlencoded" },
            body: encode({ "form-name": "lead-form", ...values })
          })
          .then(() => {
            console.log(values);
            alert('Success');
          })
          .catch(() => {
            alert('Error');
          })

        })
       }
      }
    >
      <WizardStep
        onSubmit={() => console.log("Step1 onSubmit")}
        validationSchema={Yup.object({
          firstName: Yup.string().required("Nome obrigatĂłrio"),
          lastName: Yup.string().required("Sobrenome obrigatĂłrio"),
          email: Yup.string()
          .email("E-mail inválido")
          .required("E-email obrigatĂłrio")
        })}
      >
        <StepTitle>Sobre VocĂŞ</StepTitle>
        <div>

          <InputForm
            autoComplete="given-name"
            component="input"
            id="firstName"
            name="firstName"
            placeholder="Nome"
            type="text"
          />
          <ErrorMsg className="error" component="div" name="firstName" />
        </div>

        <div>
          <InputForm
            autoComplete="family-name"
            component="input"
            id="lastName"
            name="lastName"
            placeholder="Last Name"
            type="text"
          />
          <ErrorMsg className="error" component="div" name="lastName" />
        </div>
        <div>
          <InputForm
            autoComplete="email"
            component="input"
            id="email"
            name="email"
            placeholder="E-mail"
            type="text"
          />
          <ErrorMsg className="error" component="div" name="email" />
        </div>  
      </WizardStep>
      <WizardStep
        onSubmit={() => console.log("Step2 onSubmit")}
        validationSchema={Yup.object({
          cnpj: Yup.string().required("CNPJ obrigatĂłrio")
        })}
      >
        <StepTitle>Sobre a Empresa</StepTitle>

        <div>
          <InputForm
            autoComplete="company-cnpj"
            component="input"
            id="cnpj"
            name="cnpj"
            placeholder="CNPJ"
            type="text"
          />
          <ErrorMsg className="error" component="div" name="cnpj" />
        </div>  
      </WizardStep>
    </Wizard>
    </FieldSet>
  </Container>
);

Hi @antonelli182 :wave:t2:

I’m going to be testing this specific case tomorrow in preparation for an article I’ll be writing, but I have a hunch that the reason you’re not getting that field in your Forms UI is because the build bots that scan your static HTML and transform your <form> a little bit also take note of specifically what inputs are on that form by name=. My hypothesis is that since you don’t have an HTML field called out for that key that you’re sending, it ignores that data. I’m not saying you have to use or even interact with the physical input, but I would bet that adding

<input type="hidden" name="cnjp" />

right below your hidden form-name input, and changing nothing else, it works.

Give that a try and let me know :slight_smile:

–
Jon

1 Like

Dude that worked perfectly! :clap:
Really appreciate the help @jonsully
Take care man!