I recently tried adding a Turnstile captcha to the Fancybox modal (latest and some random versions) and I failed. Fancybox in some strange way copies/changes DOM elements and turnsile gets display:none. But recaptcha works fine (
I prepared an example: https://codepen.io/queri/pen/OJrvYOx
I know it’s a bit old question but still answering it as it might help someone. Found a solution to make it work.
<script>
var cfWidgetId = '';
Fancybox.bind("[data-fancybox]", {
on: {
reveal: (fancybox, slide) => {
const widgetElement = document.getElementById('cf-turnstile');
// Initialize Turnstile only when modal is opened
if (!widgetElement.hasAttribute('data-initialized')) {
cfWidgetId = turnstile.render('#cf-turnstile', { // Get widget id
sitekey: 'your-sitekey',
callback: function(token) {
console.log("CAPTCHA completed.");
}
});
// Mark as initialized to prevent re-initialization
widgetElement.setAttribute('data-initialized', 'true');
}
},
close: (fancybox, slide) => {
// Optional: Reset Turnstile on modal close if needed
const widgetElement = document.getElementById('cf-turnstile');
if (widgetElement.hasAttribute('data-initialized')) {
widgetElement.removeAttribute('data-initialized');
widgetElement.innerHTML = ''; // Clear the widget instance on close
if (cfWidgetId != '') {
turnstile.remove(cfWidgetId); // Pass widget id to destroy it on close as it will be re initiated on opening of the modal again
}
}
}
}
});
</script>
So apparently, there are a couple of things that need to be handled correctly:
Turnstile should not be initialized on a hidden element: Since Fancybox hides the modal initially, the Turnstile widget can’t render properly until the modal is visible.
Ensure the widget re-renders correctly when opening and closing the modal: If you’re opening and closing the modal multiple times, the widget may need to be destroyed and re-initialized to avoid rendering problems.
Key Fixes:
Defer Rendering: The Turnstile widget is rendered only after the modal is opened. This is done in the reveal event provided by Fancybox, which ensures that the widget is initialized only when the modal is visible.
Prevent Re-initialization: The widget is marked as initialized using a custom data-initialized attribute to avoid rendering the widget every time the modal is opened.
Widget Cleanup on Close (Optional): The widget is optionally destroyed on modal close by clearing its content, so it can be re-rendered cleanly next time the modal is opened. This is useful if you encounter multiple rendering issues when reopening the modal.