Multiple Turnstile components on a page not working
aprilnickelgc opened this issue · 2 comments
Do you want to request a feature or report a bug?
Bug
What is the current behavior?
Hello! I'd like to render multiple forms on one page, each with its own Turnstile widget. When I do this, only the last one renders the Turnstile widget.
Note: If you make a change to the first component (for example, remove the cData
option, line 18, in the CodeSandbox linked below), the hot reload makes the widget render & get the token. Now, if you make a change to the second component (remove the cData
option, line 31 now), you'll see the second widget show up - and now both widgets, with tokens, are on the page, which looks like it's fixed. However, if you refresh the browser pane, only the second Turnstile widget shows up - same as when the CodeSandbox originally loaded.
Screenshot of just one widget working on initial page load:
If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have dependencies other than React. Paste the link to your CodeSandbox example below:
https://codesandbox.io/s/distracted-resonance-jy1lg2?file=/src/App.tsx
What is the expected behavior?
Each form's Turnstile component should render the widget & get the token returned back.
Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
- React: react@17.0.2
- Browser: Brave [Version 1.49.128 Chromium: 111.0.5563.110 (Official Build) (x86_64)]
- I have not tried any other versions of React, so can't comment on whether it worked in previous versions.
Hey @aprilnickelgc , thanks for submitting this issue. I agree this should not happen. I'll describe why this happened:
The library automatically injects the Cloudflare script and assigns an onload
function where we actually render the widget.
In version 0.1.2 and older, the only way to render more than one widget is by expliciting specifyng custom and unique scriptOptions.id
and scriptOptions.onLoadCallbackName
, with this the library injects an unique script per widget.
Something like this:
import { Turnstile } from '@marsidev/react-turnstile'
export default function Widgets() {
return (
<>
<Turnstile siteKey='1x00000000000000000000AA' />
<Turnstile
scriptOptions={{
id: "second-script",
onLoadCallbackName: "secondCallback"
}}
siteKey='1x00000000000000000000AA' />
</>
)
}
Here is an example using this strategy.
As you did not specified a custom scriptOptions.id
and scriptOptions.onLoadCallbackName
in the second widget, the library does not inject the second script and consequently does not run the onload
function where we do the rendering.
I know that adding multiple script tags is not viable, so I changed the strategy of the script injection (PR) so in next version we can render multiple widgets with a single script tag. The only requirement is make sure each widget has an unique id
:
import { Turnstile } from '@marsidev/react-turnstile'
export default function Widgets() {
return (
<>
<Turnstile id='widget-1' siteKey='1x00000000000000000000AA' />
<Turnstile id='widget-2' siteKey='1x00000000000000000000AA' />
</>
)
}
I included this in the docs
Also there is a new demo page where I use multiple widgets. Is not merged yet but you will be able to see it very soon at https://react-turnstile.vercel.app/multiple-widgets
Amazing, thank you for the in depth explanation & the fix! 💪