User tests: Successful: Unsuccessful:
Pull Request resolves #47812
Fix validate.js so that fields hidden via showon.js are correctly skipped during form validation. The previous implementation incorrectly used getAttribute('display'), which is not valid for detecting visibility. This has been replaced with getComputedStyle() to properly detect hidden elements, including those hidden through parent containers.
Hidden fields controlled by showon.js are still validated, causing errors such as:
"The invalid form control with name='jform[...]' is not focusable"
Fields hidden via showon.js are excluded from validation and do not trigger validation errors.
| Status | New | ⇒ | Pending |
| Category | ⇒ | JavaScript Repository NPM Change Front End Plugins |
| Labels |
Added:
NPM Resource Changed
PR-5.4-dev
|
||
| Category | JavaScript Repository NPM Change Front End Plugins | ⇒ | Administration JavaScript Repository NPM Change Front End Plugins |
| Category | JavaScript Repository NPM Change Front End Plugins Administration | ⇒ | JavaScript Repository NPM Change |
Cleaned up the PR and removed the unrelated commits. CI has been re-triggered.
@jiteshkhatri11 Please confirm the Generative AI policy at the top of your pull request. That is part of the pull request template which you see when creating a new pull request, and you should not have removed that. Thanks in advance.
Thanks, I’ve added the Generative AI policy section in the PR description.
Hi @jiteshkhatri11, thank you for your first time contribution.
Could you please this template?
Pull Request resolves # .
- [ ] I read the [Generative AI policy](https://developer.joomla.org/generative-ai-policy.html) and my contribution is either not created with the help of AI or is compatible with the policy and GNU/GPL 2 or later.
### Summary of Changes
### Testing Instructions
### Actual result BEFORE applying this Pull Request
### Expected result AFTER applying this Pull Request
### Link to documentations
Please select:
- [ ] Documentation link for guide.joomla.org: <link>
- [ ] No documentation changes for guide.joomla.org needed
- [ ] Pull Request link for manual.joomla.org: <link>
- [ ] No documentation changes for manual.joomla.org neededHi @jiteshkhatri11, thank you for your first time contribution.
Could you please use this template?
Pull Request resolves # .
- [ ] I read the [Generative AI policy](https://developer.joomla.org/generative-ai-policy.html) and my contribution is either not created with the help of AI or is compatible with the policy and GNU/GPL 2 or later.
### Summary of Changes
### Testing Instructions
### Actual result BEFORE applying this Pull Request
### Expected result AFTER applying this Pull Request
### Link to documentations
Please select:
- [ ] Documentation link for guide.joomla.org: <link>
- [ ] No documentation changes for guide.joomla.org needed
- [ ] Pull Request link for manual.joomla.org: <link>
- [ ] No documentation changes for manual.joomla.org neededThanks for the feedback. I’ve updated the PR to follow the required template, including the Generative AI policy checkbox and full structured sections (summary, testing instructions, and expected/actual results). Please let me know if any further changes are needed.
Can I suggest you use https://developer.mozilla.org/en-US/docs/Web/API/Element/checkVisibility rather than getComputedStyle?
getComputedStyle is quite an old method which returns a huge object of CSS properties for said element.
I've created a JS Fiddle showcasing an example of checkVisibility(): https://jsfiddle.net/fjuq52vk/
Your new code might look something like:
const isElementHidden = !element.checkVisibility({
visibilityProperty: true,
});
if (element.getAttribute('disabled') === 'disabled' || isElementHidden) {
this.handleResponse(true, element);
return true;
}
Can I suggest you use https://developer.mozilla.org/en-US/docs/Web/API/Element/checkVisibility rather than getComputedStyle?
getComputedStyle is quite an old method which returns a huge object of CSS properties for said element.
I've created a JS Fiddle showcasing an example of checkVisibility(): https://jsfiddle.net/fjuq52vk/
Your new code might look something like:
const isElementHidden = !element.checkVisibility({
visibilityProperty: true,
});
if (element.getAttribute('disabled') === 'disabled' || isElementHidden) {
this.handleResponse(true, element);
return true;
}
Updated the validation visibility check to use checkVisibility() as suggested. The rest of the file remains unchanged.
Thanks for the suggestion!
Thanks @jiteshkhatri11 for this PR.
This fix doesn't work. display is set to 'block' even if the parent element has display = 'none', likely because display is not an inherited CSS property so getComputedStyle() will always return the display state of the element itself ('block') and not of the parent ('none').
So you should create a function that 'walks up the DOM tree' and checks if any of the parent element has display = 'none'.
or some other clever trick, not a JS developer myself :)
Thanks for testing and for the explanation.
You're right — checking only the element's computed display state does not work when one of the parent containers is hidden by showon.js.
I've updated the logic to walk up the DOM tree and detect hidden parent elements before validation is executed.
Hi, so works but doesn't solve the issue:
so now the hidden fields gets handled correct: yeay, but....
I still get the error "The invalid form control with name=‘jform[extra_Security_contact_form_extra_fields0]’ is not focusable." preventing the submission of the form.
The issue here is the browser doing its own validation (which it always does): when I look at the field that is hidden by showon.js I noticed that the parent got the hidden class, but the field itself was not stripped from the required attribute.
Because the field jform[extra_Security_contact_form_extra_fields0] had attribute required, the browser as a final step before submitting tries to validate it (it is required) and fails (because it is empty) giving the error message.
So the fix here is not only in validate.js, but also in showon.js not removing the attribute 'required' and adding the attribute 'data-requied-removed'
does this make sense?
Hi, so works but doesn't solve the issue:
so now the hidden fields gets handled correct: yeay, but....
I still get the error "The invalid form control with name=‘jform[extra_Security_contact_form_extra_fields0]’ is not focusable." preventing the submission of the form.
The issue here is the browser doing its own validation (which it always does): when I look at the field that is hidden by showon.js I noticed that the parent got the hidden class, but the field itself was not stripped from the required attribute.
Because the field jform[extra_Security_contact_form_extra_fields0] had attribute required, the browser as a final step before submitting tries to validate it (it is required) and fails (because it is empty) giving the error message.
So the fix here is not only in validate.js, but also in showon.js not removing the attribute 'required' and adding the attribute 'data-requied-removed'
does this make sense?
PS: in my work around that is exactly what I do in my JS script > add an event listener on joomla:showon-hide and then remove the required and add the was-required attribute. on the joomla:showon-show i can then revert that
I added my workaround into showon.js
// If conditions are satisfied show the target field(s), else hide
if (field.tagName !== 'option') {
if (showfield) {
field.classList.remove('hidden');
field.querySelectorAll('[data-required-removed]').forEach(el => {
el.setAttribute('required', '');
el.removeAttribute('data-required-removed');
});
field.dispatchEvent(new CustomEvent('joomla:showon-show', {
bubbles: true
}));
} else {
field.classList.add('hidden');
field.querySelectorAll('[required]').forEach(el => {
el.setAttribute('data-required-removed', '');
el.removeAttribute('required');
});
field.dispatchEvent(new CustomEvent('joomla:showon-hide', {
bubbles: true
}));
}
} else {
// @todo: If chosen or choices.js is active we should update them
field.disabled = !showfield;
}
now it works: not tested if this breaks anything else (e.g. on the back-end where showon.js is heavilly used)
I've updated the validation logic to properly detect fields hidden through parent containers by walking up the DOM tree and checking computed display state.
The implementation has also been cleaned up and re-tested locally against fields hidden by showon.js.
Please let me know if you'd still prefer handling the required attribute directly inside showon.js instead.
Hi,
Removing the required attribute is imo the responsibility of showon.
When not using validate.js but using showing, the you have this issue because it is the browser validation that fails.
And maybe (that is something I can test): if showon removes the required attribute when Hiddes, the issue is also fixed without changing validate.js
Just theory, currently not online so cannot test this
I can test this after the weekend
Thanks for the feedback. I agree that the root cause is browser validation triggered by required attributes on hidden fields.
I will update showon.js to handle removal and restoration of the required attribute when fields are hidden/shown, so native validation does not trigger incorrectly.
I will simplify validate.js accordingly to avoid overlapping responsibilities.
ok, so as it turns out, the only thing needed is this fix (#47824 (comment)) in showon.js
with this fix the form submission works (with unmodified validate.js), without it the form will not submit.
so as for my initial bugreport, only the showon.js fix I provided is required.
Although I also see that the validate.js change you proposed is an actual improvement, but that is not for me to decide.
That @jiteshkhatri11 for doing all the work you do here, appreciate it.
Also, as putting in the work is not a guarantee this will be implemented I will add below the workaround I have in my extensions. Maybe when somebody runs into this has some use for it, or when your PR is implemented, it will likely not be back-ported.
// Listeners attached immediately (outside DOMContentLoaded) so they are active
// before validate.js attachToForm() or showon.js DOMContentLoaded handlers run.
// Workaround for Joomla validator bug: getAttribute('display') never matches,
// so hidden required fields block submission. We strip/restore required + required
// class so attachToForm() cannot re-add the attribute on hidden fields.
document.addEventListener('joomla:showon-hide', (e) => {
e.target.querySelectorAll('[required], .required').forEach((el) => {
el.dataset.wasRequired = '1';
el.removeAttribute('required');
el.classList.remove('required');
});
});
document.addEventListener('joomla:showon-show', (e) => {
e.target.querySelectorAll('[data-was-required]').forEach((el) => {
el.setAttribute('required', '');
el.classList.add('required');
el.removeAttribute('data-was-required');
});
});
document.addEventListener("DOMContentLoaded", (event) => {
OCH.initShowonRequired();
/**
* Initial scan for fields already hidden on page load.
* Uses setTimeout so it runs after all DOMContentLoaded handlers (showon, validate.js
* attachToForm) have completed — preventing attachToForm from re-adding the
* required attribute to hidden fields that still carry class="required".
*/
OCH.initShowonRequired = () => {
setTimeout(() => {
document.querySelectorAll('.control-group.hidden [required], .control-group.hidden .required').forEach((el) => {
el.dataset.wasRequired = '1';
el.removeAttribute('required');
el.classList.remove('required');
});
}, 0);
};
Thanks for the testing and detailed investigation, @Ruud68.
Your findings make sense. After reviewing the behavior again, I agree that the root cause is the browser's native validation rather than validate.js. Since fields hidden by showon.js still retain the required attribute, the browser blocks form submission before Joomla's validation logic becomes relevant.
Based on your testing, I'll rework the PR to focus on showon.js by removing the required attribute when fields are hidden and restoring it when they become visible again. I'll also review whether the current validate.js changes should be removed or submitted separately as an independent improvement.
Thanks again for taking the time to test this thoroughly and for sharing the workaround and implementation details.
Please remove the unrelated changes