marsidev / react-turnstile

Cloudflare Turnstile integration for React.
https://www.npmjs.com/package/@marsidev/react-turnstile
MIT License
414 stars 25 forks source link

Make an invisible Turnstile component show up for forced challenge? #59

Closed crisog closed 7 months ago

crisog commented 7 months ago

Sometimes the verification prompts for a manual verification, but if the component has been set to 'invisible' it won't show up.

image

Is there a way we can make it so if the challenge requires interactive action it turns visible? or would this be too complicated.

jayhemsley commented 7 months ago

Managed mode is the only way that this can be done, it would be pointless to use the Invisible and Non-Interactive modes with this method. You can conditionally show it though when it has to show up via onBeforeInteractive like this:

'use client';

export function CaptchaInput({
  className,
  name,
}: CaptchaInputProps): React.ReactElement<CaptchaInputProps> {
  const [captchaVisible, setCaptchaVisible] = useState<boolean>(false);
  const [captchaToken, setCaptchaToken] = useState<string>('');

  const { register, setValue } = useFormContext();

  useEffect(() => {
    if (captchaToken) setValue(name, captchaToken);
  }, [captchaToken]);

  return (
    <div
      className={cn([
        !captchaVisible && 'hidden',
        className,
      ])}>
      <input
        className="hidden"
        type="hidden"
        {...register(name, {
          required: true,
        })}
      />
      <Turnstile
        siteKey={xxx}
        onSuccess={(token) => setCaptchaToken(token)}
        onBeforeInteractive={() => setCaptchaVisible(true)}
      />
    </div>
  );
}

Hopefully that helps! I wanted to do the same thing.

marsidev commented 7 months ago

As @jayhemsley suggested, the onBeforeInteractive property it's what you need.

Also, the 'invisible' setting should be used when the Widget Mode is invisible too.

angelhodar commented 5 months ago

@marsidev Sorry to show up in this closed issue but I want to also implement this functionality where the widget is not visible until certain action happens (for example when you fail to login in cloudflare then the widget becomes visible). I have seen the appearance prop that does exactly this, the interaction-only option would be the same as the functionality described above. So this makes me question why did you add the extra invisible prop to the size option?

marsidev commented 5 months ago

Hey @angelhodar, good question.

size: invisible is intended to be used for Invisible Widget Types to prevent reserving a space that will never be used.

Feel free to check this PR and this issue by @chez14

If you have an idea to improve this behavior, feel free to contribute.

angelhodar commented 5 months ago

Thank you so much @marsidev !! So what is the use case of invisible widget types vs managed ones with appearance in interaction-only. Just the space that its used? I see the second one even more flexible in case interaction is needed

marsidev commented 5 months ago

Invisible widget​​:

Visitors will never interact with the Turnstile widget. Visitors will not see a widget or any indication that an invisible browser challenge is in progress.

Managed widget w/ interaction-only appearance:

The widget will become only visible in cases where an interaction is required.