Search code examples
javascriptreactjsrecaptchaformik

disable form submit button until user checks recaptcha checkbox


I'm trying to disable my form's submit button until the user clicks the Google Recaptcha checkbox 'I am not a robot'

Is there anyway to do this or do I need to download a React component specific to Google Recaptcha?

Here is my simple component that contains the Google Recaptcha:

const RecaptchaComponent = () => {
    useEffect(() => {
        // Add reCaptcha
        const script = document.createElement("script");
        script.src = "https://www.google.com/recaptcha/api.js"
        document.body.appendChild(script);
    }, [])

    return (
        <div
            className="g-recaptcha"
            data-sitekey="6LeS8_IdfdfLtQzwUgNV4545454lhvglswww14U"
        ></div>
    )
};

And here is my form's onSubmit code:

const GameForm = () => (

<div className="app">

    <Formik
        initialValues={{
            email: "",
            name: "",
            title: ""

        }}

        onSubmit={(values) => {
            //new Promise(resolve => setTimeout(resolve, 500));
            axios({
                method: "POST",
                url: "api/gameform",
                data: JSON.stringify(values),
            });
        }}
    >

        {props => {
            const {
                values,
                isSubmitting,
                handleSubmit,

            } = props;

            return (
                <form onSubmit={handleSubmit}>

                    <div>Your Game</div>

                    <label htmlFor="title">
                        Game Title:
                    </label>
                    <Field
                        id="title"
                        type="text"
                        values={values.title}
                    />

                    <label htmlFor="name">
                        Name:
                    </label>
                    <Field
                        id="name"
                        type="text"
                        value={values.name}
                    />

                    <label htmlFor="email">
                        Email:
                    </label>
                    <Field
                        id="email"
                        name="email"
                        type="email"
                        value={values.email}
                    />

                    <div>
                    <ReCAPTCHA 
                        sitekey="6LeS8_IUAAAAAhteegfgwwewqe223" 
                        onChange={useCallback(() => setDisableSubmit(false))}
 />
                    </div>
                    <div>
                        <Button type="submit">
                            Submit
                        </Button>
                    </div>
                </form>
            );
        }}
    </Formik>

</div>
);

Solution

  • You don't need to use the react component, but it's easier.

    export const MyForm = () => {
    
       const [disableSubmit,setDisableSubmit] = useState(true);
    
       return (
         ... rest of your form
         <ReCAPTCHA 
             sitekey="6LeS8_IdfdfLtQzwUgNV4545454lhvglswww14U" 
             onChange={useCallback(() => setDisableSubmit(false))}
         />
         <button type="submit" disabled={disableSubmit}>Submit</button>
       )
    
    }
    

    EDIT:

    One of my biggest pet peeves is seeing React tutorials where authors encourage devs to use functions that return JSX instead of just using functional components.

    Formik's "children as a function" pattern is gross (react-router-dom does the same thing) - it should be a component:

    const GameForm = () => {
      return <Formik ...your props>{props => <YourForm {...props}/>}</Formik>
    }
    
    const YourForm = (props) => {
       const [disableSubmit,setDisableSubmit] = useState(true);
    
    
       ... everything inside the child function in `GameForm`
    }