reactjsnext.jsstatecloudflare-turnstile

Update state on captcha status change without handleSubmit function in the form Next.js


I have a simple contact form that uses next.js API routes to send an e-mail. The form itself works well and I'd like to implement a Cloudflare Turnstile API on the client side.

My problem is as follows - i have a form that performs an action once submit button is pressed:

I will not include the unnecessary parts of code to make this easier to read

const [captcha, setCaptcha] = useState('not_verified')

<form
 action="/api/contact_form"
 method="POST">
  <Turnstile Captcha Element>
  <button type="submit" disabled={captcha === 'not_verified'}>
   Send
  </button>
</form>

Without changing the form action="/api/contact_form" how can I change state based on the captcha response? I have no problem getting the response inside of that specific API call, but I'd like for the client to not be able to even press send before they validate.


Solution

  • You can use the Turnstile component’s callback (mostly called onVerify) to update your state when a user successfully completes the captcha. Below is an example code of submit button disabeling.

    import { useState } from 'react';
    import Turnstile from '@marsidev/react-turnstile'; // Turnstile component 
    
    export default function ContactForm() {
      const [captchaToken, setCaptchaToken] = useState(null);
    
      return (
        <form action="/api/contact_form" method="POST">
          <Turnstile
            sitekey="your-site-key"
            onVerify={(token) => {
              // Update the state with the token returned by Turnstile
              setCaptchaToken(token);
            }}
            onExpire={() => {
              // Optionally reset the token when it expires
              setCaptchaToken(null);
            }}
          />
          {/* Optionally, include the token as a hidden input so it's sent with the form - not necessary */}
          <input type="hidden" name="captchaToken" value={captchaToken || ''} />
          <button type="submit" disabled={!captchaToken}>
            Send
          </button>
        </form>
      );
    }
    

    Explanation

    1. In here I initialize captchaToken as null. The submit button is disabled until captchaToken has a value.

    2. The onVerify callback of the Turnstile component fires when the user successfully completes the captcha. This callback receives a token, which we store in state using setCaptchaToken(token).

    3. Set the submit (send) button status according to whether the captcha exists or not. If it’s still null (or false), the button remains disabled. (You can also use true/false if you want instead of null.)

    Optionally

    Including a hidden input field with the token ensures that your API endpoint can also verify the token server-side.

    You need to change this as you want according to your code