@htmlbricks/hb-captcha-google-recaptcha-v2-invisible
v0.73.7
Published
Loads the Google reCAPTCHA v2 invisible SDK, renders the widget with your `api_key`, and exposes `grecaptcha.execute()` / reset when the `get` attribute changes after render. Dispatches `googleRecaptchaRendered` once mounted and `googleRecaptchaV2Response
Readme
hb-captcha-google-recaptcha-v2-invisible
Category: utilities · Tags: utilities, security
Summary
Custom element that loads Google’s reCAPTCHA v2 explicit API, mounts an invisible widget in the document light DOM, runs execution when the SDK is ready, and surfaces the verification token and render lifecycle through custom events.
What it does
- Injects
https://www.google.com/recaptcha/api.js?render=explicit(async/defer) intodocument.headwith a stable script id (recaptchav2-sdk), if not already present. - Ensures a host div exists on
document.bodywith idrecaptchav2-element,data-size="invisible", then callsgrecaptcha.render()with your site key (api_key) and a callback that dispatches the response event. - After a successful render, dispatches
googleRecaptchaRendered, then fromonMount’s load path callsgrecaptcha.execute()once the widget is ready. - Polls (starting after 1s, then 2s retries) until
window.grecaptchais available andapi_keyis set before rendering. - On teardown, removes that script node and body div, clears the polling timer, and assigns
window.grecaptchatoundefined.
How it renders
- Shadow root: Forwards Bulma + component SCSS (
styles/bulma.scss,styles/webcomponent.scss); there is no visible captcha UI inside the shadow tree. - Light DOM / Google widget: The actual reCAPTCHA widget is attached via the
recaptchav2-elementdiv appended todocument.body(not inside the custom element). Integrators should assume global script injection and a body-level placeholder, not a child of<hb-captcha-google-recaptcha-v2-invisible>.
Logic: site key, token, and get
- Site key: The
api_keyprop is passed togrecaptcha.render(..., { sitekey: api_key, callback }). - Token: When Google invokes the callback, the component dispatches
googleRecaptchaV2Responsewithdetail.response(string). The implementation also toggles internal state so a later programmatic run canreset()thenexecute()if a response was already produced (execCaptcha()). get: An$effectruns when reactive dependencies change (includingget). After the widget has rendered and an internal “ready” latch is set, ifget !== nullit callsexecCaptcha()again (execute, or reset+execute if a response was already received). Sonullsuppresses that path;undefinedand other non-nullvalues still satisfyget !== nullonce the latch is set—align testing with that condition, not only “attribute changed”.
Attributes / props (Component, snake_case)
| Name | Type (authoring) | Role |
| --- | --- | --- |
| api_key | string (optional) | reCAPTCHA site key passed to grecaptcha.render as sitekey. |
| get | optional (typed any) | Participates in the post-render $effect / execCaptcha() flow; see above (get !== null). |
HTML consumers should follow your platform’s rules for string attributes (e.g. booleans as yes / no where applicable).
Events (CustomEvent)
| Event | detail (TypeScript) |
| --- | --- |
| googleRecaptchaV2Response | { response: string } — verification token from the callback. |
| googleRecaptchaRendered | { render: true } — fired once after grecaptcha.render completes in this component. |
Styling
- Bulma theme tokens are forwarded onto
:hosteven though the captcha UI is not in the shadow tree (extra/docs.ts). - Documented CSS custom properties for catalog/style setup:
--bulma-link,--bulma-text(colors; defaults follow the forwarded Bulma theme).
Parts and slots
::part: none (cssPartsis empty).- Slots: none (
htmlSlotsis empty).
Typings
Authoring types live in types/webcomponent.type.d.ts:
Component:api_key?,get?Events:googleRecaptchaV2Response→{ response: string };googleRecaptchaRendered→{ render: true }
Example
Google’s public test site key for v2 (always passes in test mode); replace with your production key.
<hb-captcha-google-recaptcha-v2-invisible api_key="6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"></hb-captcha-google-recaptcha-v2-invisible>const el = document.querySelector("hb-captcha-google-recaptcha-v2-invisible");
el.addEventListener("googleRecaptchaRendered", (e) => {
console.log("rendered", e.detail); // { render: true }
});
el.addEventListener("googleRecaptchaV2Response", (e) => {
console.log("token", e.detail.response);
});Integrator note: CSP, domain allowlisting, and Google’s key/domain configuration apply outside this component.
