-
Notifications
You must be signed in to change notification settings - Fork 334
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix conditional reveals failing if the ID of the revealed element contains special characters #1843
Fix conditional reveals failing if the ID of the revealed element contains special characters #1843
Conversation
If the conditionally revealed element has an ID that contains characters that have a special meaning in CSS, such as `[]`, the call to `querySelector` fails because as it's being evaluated as a selector the ID needs to be escaped: ``` Uncaught DOMException: Failed to execute 'querySelector' on 'Element': '#conditional-person-1[how-contacted]-2' is not a valid selector. at Radios.<anonymous> (http://localhost:3000/public/all.js:1978:31) at NodeList.forEach (<anonymous>) at nodeListForEach (http://localhost:3000/public/all.js:14:18) at Radios.init (http://localhost:3000/public/all.js:1973:3) at http://localhost:3000/public/all.js:2384:24 at NodeList.forEach (<anonymous>) at nodeListForEach (http://localhost:3000/public/all.js:14:18) at Object.initAll (http://localhost:3000/public/all.js:2383:3) at http://localhost:3000/components/radios/with-conditional-items-and-square-brackets/preview:98:32 ``` In some cases the selector may be valid but still incorrect, like `#conditional-rejectionReasons[candidate-actions]` which would select any element with ID conditional-rejectionReasons, also having the attribute `candidate-actions`. We can avoid all of this by using `document.getElementById` instead, avoiding the ID being evaluated as a selector. The downside is that we can't constrain the scope to the `$module`. However, I don't think this should cause any issues (especially as the ID should be unique) and this avoids alternatives like using `CSS.escape` to escape the ID, which we'd then need to polyfill.
Raised as a draft as I'm worried that my Friday afternoon brain is missing a reason why changing the scope from |
If we're happy with this approach it'd probably make sense to apply the same change to the character count, which should fix #1809:
|
Thanks for digging into this! I admit that I need to dig into the original issue a bit more but these are my thoughts on swapping I think we need to be wary that some of the existing behaviour would change, even if we're talking about edge cases:
If we decide to make this change, we should probably have less trust in any elements that are queried with Also,
but with the current implementation you wouldn't be able to use If we make this change, we should also consider changing the code comment about scope to say that wherever IDs are concerned they are queried from the whole document (I don't think we have any other docs about |
Check that the checkbox aria-controls target has the `govuk-checkboxes__conditional` class before trying to toggle the `--hidden` modifier. This mirrors a similar check that we do for conditional reveals associated with radios, and makes it more robust if e.g. aria-controls is being used for things that are not conditional reveals, now that we're not scoping the aria-controls lookup to the $module.
Let's play it safe and make this change in 4.0. |
Although it’s valid to start an ID with a number, the lack of quotes makes this an invalid CSS selector when interpolated with an ID that starts with a number, and an error is thrown: > DOMException: Failed to execute 'querySelector' on 'Element': '[id=1_more-detail-info]' is not a valid selector. This is because attribute values are either `ident-tokens` or `string-tokens` [1]. Omitting the quotes means that the atrribute value is treated as an ident-token, which may not start with a number [2]. Quoting the value means it’s treated instead as a string-token, which can start with a number [3]. Ideally we’d be using `document.getElementById` to get the count message, but we’ve previously decided that would be a breaking change as it means the lookup is no longer scoped to the $module [4]. [1]: https://www.w3.org/TR/selectors/#attribute-representation [2]: https://www.w3.org/TR/css-syntax-3/#ident-token-diagram [3]: https://www.w3.org/TR/css-syntax-3/#string-token-diagram [4]: #1843 (comment)
If the conditionally revealed element has an ID that contains characters that have a special meaning in CSS, such as
[]
, the call toquerySelector
fails because as it's being evaluated as a selector the ID needs to be escaped:In some cases the selector may be valid but still incorrect, like
#conditional-rejectionReasons[candidate-actions]
which would select any element with ID conditional-rejectionReasons, also having the attributecandidate-actions
.We can avoid all of this by using
document.getElementById
instead, avoiding the ID being evaluated as a selector. The downside is that we can't constrain the scope to the$module
. However, I don't think this should cause any issues (especially as the ID should be unique) and this avoids alternatives like usingCSS.escape
to escape the ID, which we'd then need to polyfill.Fixes #1808