reCAPTCHA widget is cut off at 320px on the contact form #215

Closed
opened 2026-08-18 04:01:07 -05:00 by null · 1 comment
Owner

Found by rendering the deployed contact page. Build SHA cf92354, live at v0.9.4.

What is true now. Google's reCAPTCHA v2 checkbox widget is a fixed 304px wide and does not shrink:

viewport   iframe            result
320px      x 41 - 345 (304)  CUT OFF by 25px
360px      x 41 - 345 (304)  fits
390px      x 41 - 345 (304)  fits
414px      x 41 - 345 (304)  fits

So it only bites at or below ~344px — iPhone SE and older small Androids.

What it costs. The clipped 25px is the right-hand end of the widget, carrying the reCAPTCHA branding and the privacy/terms links. The checkbox itself is at the left and remains tappable, so the form is still submittable — this is presentation, not function, which is why P2. But Google's terms require the branding be visible where the badge is not otherwise shown, and a form visibly running off the screen edge undermines the trust the page exists to build.

As with the header CTA, overflow-x: hidden in src/index.css means there is no scrollbar to reveal it.

Where. src/components/RecaptchaPlaceholder.jsx renders an empty div inside a bordered wrapper with px-4 py-3; Google injects the 304px iframe into that div.

Fix direction. Scale the widget below ~360px rather than trying to narrow it — its width is fixed by Google and cannot be overridden by CSS on the iframe:

@media (max-width: 360px) { .recaptcha-scale { transform: scale(0.85); transform-origin: 0 0; } }

and reduce the wrapper height to match so the layout does not gain dead space.

Verify: node scripts/qa-browser.mjs --paths /contact --viewports 320 reports no element past the right edge, and the reCAPTCHA iframe's right edge is <= 320 at a 320px viewport.

Found by rendering the deployed contact page. Build SHA `cf92354`, live at v0.9.4. **What is true now.** Google's reCAPTCHA v2 checkbox widget is a fixed 304px wide and does not shrink: viewport iframe result 320px x 41 - 345 (304) CUT OFF by 25px 360px x 41 - 345 (304) fits 390px x 41 - 345 (304) fits 414px x 41 - 345 (304) fits So it only bites at or below ~344px — iPhone SE and older small Androids. **What it costs.** The clipped 25px is the right-hand end of the widget, carrying the reCAPTCHA branding and the privacy/terms links. The checkbox itself is at the left and remains tappable, so **the form is still submittable** — this is presentation, not function, which is why P2. But Google's terms require the branding be visible where the badge is not otherwise shown, and a form visibly running off the screen edge undermines the trust the page exists to build. As with the header CTA, `overflow-x: hidden` in `src/index.css` means there is no scrollbar to reveal it. **Where.** `src/components/RecaptchaPlaceholder.jsx` renders an empty div inside a bordered wrapper with `px-4 py-3`; Google injects the 304px iframe into that div. **Fix direction.** Scale the widget below ~360px rather than trying to narrow it — its width is fixed by Google and cannot be overridden by CSS on the iframe: @media (max-width: 360px) { .recaptcha-scale { transform: scale(0.85); transform-origin: 0 0; } } and reduce the wrapper height to match so the layout does not gain dead space. Verify: `node scripts/qa-browser.mjs --paths /contact --viewports 320` reports no element past the right edge, and the reCAPTCHA iframe's right edge is <= 320 at a 320px viewport.
null added this to the Batch 16 — Viewport defects found by browser measurement milestone 2026-08-18 04:01:07 -05:00
null added the
P2
label 2026-08-18 04:01:07 -05:00
Author
Owner

Fixed in 231f07c, released as v0.9.5 and DEPLOYED to production on 2026-08-18.

Google's iframe is still exactly 304px — that cannot be changed — so the wrapper is scaled instead. .recaptcha-scale in src/index.css applies transform: scale(0.85) with transform-origin: 0 0 below 360px, and sets an explicit 66px height because transform does not affect layout and the form would otherwise keep reserving the full-size box and gain a strip of dead space.

Measured on the live contact page at 320px:

before   iframe x 41 - 345   viewport 320   CUT OFF by 25px
after    iframe x 41 - 299   viewport 320   FITS, 21px clear

The branding and the privacy/terms links are fully visible again. Checked at 360, 768, 800 and 1024 as well — unchanged there, since the media query only applies at 360 and below.

scripts/qa-browser.mjs --paths /contact --viewports 320 reports no element past the right edge, where before it reported three.

Verify: at a 320px viewport on https://queuenorth.com/contact, the reCAPTCHA iframe's getBoundingClientRect().right is 299 against a viewport of 320.

Fixed in 231f07c, released as v0.9.5 and DEPLOYED to production on 2026-08-18. Google's iframe is still exactly 304px — that cannot be changed — so the wrapper is scaled instead. `.recaptcha-scale` in src/index.css applies `transform: scale(0.85)` with `transform-origin: 0 0` below 360px, and sets an explicit 66px height because transform does not affect layout and the form would otherwise keep reserving the full-size box and gain a strip of dead space. Measured on the live contact page at 320px: before iframe x 41 - 345 viewport 320 CUT OFF by 25px after iframe x 41 - 299 viewport 320 FITS, 21px clear The branding and the privacy/terms links are fully visible again. Checked at 360, 768, 800 and 1024 as well — unchanged there, since the media query only applies at 360 and below. `scripts/qa-browser.mjs --paths /contact --viewports 320` reports no element past the right edge, where before it reported three. Verify: at a 320px viewport on https://queuenorth.com/contact, the reCAPTCHA iframe's getBoundingClientRect().right is 299 against a viewport of 320.
null closed this issue 2026-08-18 04:08:57 -05:00
Sign in to join this conversation.
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: null/Queue-North-Website#215
No description provided.