Search code examples
javascripthtmlcssrecaptchareact-google-recaptcha

How to change Google reCAPTCHA (v2) theme dynamically?


I'm working on a Bootstrap website that has light and dark mode, functioning through JavaScript. And I've integrated Google reCAPTCHA (v2) (I'm not a robot) into my project successfully.

But I want to be able to change reCAPTCHA theme dynamically through the theme toggle switch. As the documentation has an attribute data-theme which we can set value to dark or light.

The main div of reCAPTCHA container through which the theme could be toggled by changing class (rc-anchor-light / rc-anchor-dark) is located inside an iframe.

I tried by adding and removing classes (rc-anchor-light / rc-anchor-dark) from the theme switch JavaScript function to change the reCAPTCHA theme dynamically, but it's not working and I'm not able to figure out why.


Solution

  • While reCAPTCHA v2 doesn't natively support dynamic theme switching, here's a workaround using multiple reCAPTCHA containers and JavaScript:

    HTML structure for two reCAPTCHA containers with different themes

    <div class="rg-recaptcha border rounded hide" id="grecaptchaLight" data-callback="recaptchaVe" data-expired-callback="recaptchaEx" data-theme="light"></div>
    <div class="rg-recaptcha border rounded hide" id="grecaptchaDark"  data-callback="recaptchaVe" data-expired-callback="recaptchaEx" data-theme="dark"></div>
    

    JavaScript:

    // Function to determine the preferred theme (light or dark)
    
    function getPreferredThemeFunction() {
        // Implement your logic to determine the preferred theme here
        // This function should return 'light' or 'dark'
    }
    
    // Variable to store the preferred theme
    var preferredTheme = getPreferredThemeFunction();
    
    // Variables to store the reCAPTCHA widget IDs
    var grecaptchaDarkWD, grecaptchaLightWD;
    
    // Variable to track whether reCAPTCHA has been rendered
    var gCapthaRendered = false;
    
    // Callback function triggered when reCAPTCHA is loaded
    var onloadCallback = function () {
        // Render reCAPTCHA widgets with dark and light themes
        grecaptchaDarkWD = grecaptcha.render('grecaptchaDark', {
            'sitekey': '1234567890',
            'theme': 'dark'
        });
    
        grecaptchaLightWD = grecaptcha.render('grecaptchaLight', {
            'sitekey': '1234567890',
            'theme': 'light'
        });
    
        // Mark reCAPTCHA as rendered
        gCapthaRendered = true;
    
        // If a preferred theme is set, switch to it
        if (preferredTheme) {
            changeReCaptcha(preferredTheme);
        }
    };
    
    // Function to dynamically change the reCAPTCHA theme
    function changeReCaptcha(theme = 'light') {
        if (gCapthaRendered) {
            // Reset and hide the inactive reCAPTCHA container
            if (theme == 'dark') {
                document.getElementById('grecaptchaLight').innerHTML = "";
                grecaptcha.reset(grecaptchaDarkWD);
                document.getElementById('grecaptchaLight').classList.add("hide");
                document.getElementById('grecaptchaDark').classList.remove("hide");
            } else if (theme == 'light') {
                document.getElementById('grecaptchaDark').innerHTML = "";
                grecaptcha.reset(grecaptchaLightWD);
                document.getElementById('grecaptchaDark').classList.add("hide");
                document.getElementById('grecaptchaLight').classList.remove("hide");
            }
        }
    }