Forms: Make single Checkbox row fully clickable (FORMS-684)#48585
Forms: Make single Checkbox row fully clickable (FORMS-684)#48585alinclamba wants to merge 1 commit intotrunkfrom
Conversation
FORMS-684 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Are you an Automattician? Please test your changes on all WordPress.com environments to help mitigate accidental explosions.
Interested in more tips and information?
|
|
Thank you for your PR! When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:
This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖 Follow this PR Review Process:
If you have questions about anything, reach out in #jetpack-developers for guidance! |
Code Coverage SummaryThis PR did not change code coverage! That could be good or bad, depending on the situation. Everything covered before, and still is? Great! Nothing was covered before? Not so great. 🤷 |
|
Ran |
Fixes #41522
Linear: FORMS-684
On a Jetpack Form, clicking the empty space between a single Checkbox input and its label text did nothing. Only the input itself and the label text were clickable. This narrows the click target and is inconsistent with how the Radio and Multi-Choice fields already behave.
Proposed changes
projects/packages/forms/src/contact-form/class-contact-form-field.php, swap the<input>and<label>open-tag lines insiderender_checkbox_field()so the<label>wraps the<input>instead of being its sibling.Root cause
render_checkbox_field()emits the<input>and<label>as siblings inside a wrapper<div>:The wrapper is a
<div>, not a<label>, so clicks in the gap between the input and the label text don't toggle the input. Browsers only forward clicks to a checkbox via the input itself or via a<label>that either wraps it or is associated with it through a labelable click target — the gap belongs to the<div>and isn't either.Fix
Move the
<label>open tag above the<input>so the label wraps the input:This matches the convention already used by:
render_consent_field)optionsdatarendering path (refactored as a side effect of FORMS-131, PR Forms: use entire button area for selecting multi-select options #46263, merged Dec 2025)optionsdatarendering path (refactored as a side effect of PR Forms: Add 'Other' option support to radio fields #46461)The original GitHub issue #41522 reported this bug for single Checkbox, Radio, and Multi-Choice. Radio and Multi-Choice were fixed incidentally by the two PRs above; single Checkbox has its own dedicated render path that wasn't touched. This PR addresses only that remaining path.
What is intentionally not changed
for=attribute on the label is kept. It's now redundant for click association (the wrapping handles it) but keeping it costs nothing and avoids breaking any external tool that might key off it.id=attribute on the input is kept. It's reused byget_error_div( $id, 'checkbox' )so it has to stay.<div class="contact-form__checkbox-wrap">wrapper is kept. It diverges fromrender_consent_field()'s pattern (which has no equivalent wrapper), but removing it would be a separate structural change with its own theme-compatibility risk (the class is public-facing CSS, possibly targeted by external theme stylesheets) and is out of scope for this PR..contact-form__checkbox-wrap { display: inline-flex; align-items: baseline }rule continues to apply at the wrapper level. Visual parity with the previous rendering was confirmed manually on Twenty Twenty-Five with no observed regressions.jetpack/optionblock) and the bug only ever manifested on the published frontend.Visual evidence
Before (no fix), recorded on a sandbox without the FORMS-684 patch:
After (with fix), recorded on
impossibly-literary.jurassic.ninjawith the build deployed:Testing instructions
Does this pull request change what data or activity we track or use?
No. No data, schema, or API changes.
Notes
field-checkbox/edit.js+ the innerjetpack/optionblock) renders the checkbox via<RichText>and a non-interactive<input>in a different DOM shape; this PR only affects the published frontend.