SyntaxError: Failed to execute 'querySelector' on 'Element': '#div-2.1' is not a valid selector
Prerequisites
- [X] I have searched for duplicate or closed issues
- [X] I have validated any HTML to avoid common problems
- [X] I have read the contributing guidelines
Describe the issue
#35566 didn't fix things for all weird IDs. The test case addition below causes the error in the issue title.
Reduced test cases
diff --git a/js/tests/unit/scrollspy.spec.js b/js/tests/unit/scrollspy.spec.js
index c7951e6..704b52a 100644
--- a/js/tests/unit/scrollspy.spec.js
+++ b/js/tests/unit/scrollspy.spec.js
@@ -341,11 +341,13 @@ describe('ScrollSpy', () => {
' <ul class="nav">',
' <li class="nav-item"><a class="nav-link" id="a-1" href="#div-1">div 1</a></li>',
' <li class="nav-item"><a class="nav-link" id="a-2" href="#div-2">div 2</a></li>',
+ ' <li class="nav-item"><a class="nav-link" id="a-2.1" href="#div-2.1">div 2</a></li>',
' </ul>',
'</nav>',
'<div class="content" style="overflow: auto; height: 50px">',
' <div id="div-1" style="height: 100px; padding: 0; margin: 0">div 1</div>',
' <div id="div-2" style="height: 200px; padding: 0; margin: 0">div 2</div>',
+ ' <div id="div-2.1" style="height: 200px; padding: 0; margin: 0">div 2.1</div>',
'</div>'
].join('')
What operating system(s) are you seeing the problem on?
macOS
What browser(s) are you seeing the problem on?
Firefox
What version of Bootstrap are you using?
v5.2.3
@larseggert this is weird...
did not take the time to look at, but If I copy-paste:
const parseSelector = selector => {
if (selector && window.CSS && window.CSS.escape) {
// document.querySelector needs escaping to handle IDs (html5+) containing for instance /
selector = selector.replaceAll(/#([^\s"#']+)/g, (match, id) => '#' + CSS.escape(id))
}
return selector
}
in my JS Console in Firefox, and then I type:
parseSelector("#div-2.1")
"#div-2\\.1"
=> Looks like the correct result to me
Hm. Apply the patch and run the tests? That should recreate the issue. (Maybe that function isn't called?)
Here is the test failure I get with the patch above:
Chrome Headless 109.0.5414.87 (Mac OS 10.15.7) ScrollSpy constructor should add the active class to the correct element FAILED
SyntaxError: Failed to execute 'querySelector' on 'Element': '#div-2.1' is not a valid selector.
error properties: Object({ code: 12, INDEX_SIZE_ERR: 1, DOMSTRING_SIZE_ERR: 2, HIERARCHY_REQUEST_ERR: 3, WRONG_DOCUMENT_ERR: 4, INVALID_CHARACTER_ERR: 5, NO_DATA_ALLOWED_ERR: 6, NO_MODIFICATION_ALLOWED_ERR: 7, NOT_FOUND_ERR: 8, NOT_SUPPORTED_ERR: 9, INUSE_ATTRIBUTE_ERR: 10, INVALID_STATE_ERR: 11, SYNTAX_ERR: 12, INVALID_MODIFICATION_ERR: 13, NAMESPACE_ERR: 14, INVALID_ACCESS_ERR: 15, VALIDATION_ERR: 16, TYPE_MISMATCH_ERR: 17, SECURITY_ERR: 18, NETWORK_ERR: 19, ABORT_ERR: 20, URL_MISMATCH_ERR: 21, QUOTA_EXCEEDED_ERR: 22, TIMEOUT_ERR: 23, INVALID_NODE_TYPE_ERR: 24, DATA_CLONE_ERR: 25 })
at Object.findOne (js/src/dom/selector-engine.js:41:44 <- js/tests/unit/scrollspy.spec.js:9260:46)
at ScrollSpy._initializeTargetsAndObservables (js/src/scrollspy.js:211:48 <- js/tests/unit/scrollspy.spec.js:15411:76)
at ScrollSpy.refresh (js/src/scrollspy.js:91:10 <- js/tests/unit/scrollspy.spec.js:15227:12)
at new ScrollSpy (js/src/scrollspy.js:73:10 <- js/tests/unit/scrollspy.spec.js:15207:12)
at js/tests/unit/scrollspy.spec.js:355:27 <- js/tests/unit/scrollspy.spec.js:15743:29
at new Promise (<anonymous>)
at UserContext.<anonymous> (js/tests/unit/scrollspy.spec.js:338:14 <- js/tests/unit/scrollspy.spec.js:15740:16)
at <Jasmine>
```
OK, I'm not familiar with the bootstrap code, but to me it looks like scrollspy uses various SelectorEngine functions (find, etc.) that don't seem to call parseSelector at all?
I have a similar problem but with a tab linking to an external PDF file, using the "file.pdf#page=10" format.
<a href="http://example.com/document.pdf#page=10" target="_blank" class="nav-link">External link</a>
I got JS errors:
Uncaught DOMException: Document.querySelector: '#page=10' is not a valid selector
+1. I am also seeing this issue on Bootstrap v5.2.3, running Microsoft Edge v112 on Windows 11.
<h2 id="2-partition-normalized-cut">2-partition: Normalized Cut</h2>
causes the error
Uncaught DOMException: Failed to execute 'querySelector' on 'Element': '#2-partition-normalized-cut' is not a valid selector.
at Object.findOne (https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js:6:10283)
at Be._initializeTargetsAndObservables (https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js:6:53059)
at Be.refresh (https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js:6:51311)
at new Be (https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js:6:51184)
at Be.getOrCreateInstance (https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js:6:8552)
at https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js:6:54113
at i (https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js:6:4608)
It seems like #34412 (which was supposed to be closed by #35566) is actually still not solved.
Can confirm on 5.3.2.
Patching SelectorEngine.findOne() like so fixes (that part of...) scrollspy for me and my #2-foo-bar IDs. (not checked for side-effects!)
findOne(selector, element = document.documentElement) {
- return Element.prototype.querySelector.call(element, selector);
+ return Element.prototype.querySelector.call(element, parseSelector(selector));
},
the SelectorEngine.findOne() expects a css selector as valid parameter.
Scrollspy, the caller simply does not escape it: https://github.com/twbs/bootstrap/blob/0a005b36048d549057f8b551b2d19ca043a9a4c0/js/src/scrollspy.js#L213
It seams of but maybe someone want to find one element
#theId.myClass => SelectorEngine should not try to escape it.