querySelector works in Chrome 4+, Edge 12+, Firefox 3.5+, Safari 3.1+, Opera 10+, and IE 9+. Learn the syntax, use cases, and known issues.

Prince Dewani
May 2, 2026
querySelector is a DOM method in the WHATWG DOM standard that returns the first element matching a CSS selector. It works in Chrome 4+, Edge 12+, Firefox 3.5+, Safari 3.1+ on macOS and iOS 3.2+, Opera 10+, Samsung Internet 4+, Android Browser 2.1+, and Internet Explorer 9+, with partial support in IE 8.
This guide covers what querySelector is, the browsers that support it, the syntax, the use cases, how it differs from querySelectorAll and getElementById, and the known issues.
querySelector is a DOM method that returns the first Element in a document, element subtree, or DocumentFragment that matches a CSS selector string. The WHATWG DOM standard defines it on the Document, Element, and DocumentFragment interfaces, and a SyntaxError is thrown when the selector string is invalid.
Every browser shipped today supports querySelector across desktop, Android, iPadOS, and iOS, and global support sits at 97% for querySelector and querySelectorAll combined.
Chrome supports querySelector from Chrome 4 on Windows, macOS, Linux, ChromeOS, and Android. Every Chrome version since the first stable release exposes the method on Document, Element, and DocumentFragment, and Chrome for Android picks it up through the same Blink pipeline.
Edge supports querySelector from Edge 12 on Windows, macOS, Linux, and Android. The pre-Chromium EdgeHTML engine carried the method forward from Internet Explorer 9, and Chromium-based Edge 79+ ships the modern Blink implementation with no flag.
Firefox supports querySelector from Firefox 3.5 on Windows, macOS, Linux, and Android. Firefox 2 and 3 did not ship the method, and Mozilla shipped both Document.querySelector and Element.querySelector in the same Firefox 3.5 release.
Safari supports querySelector from Safari 3.1 on macOS. WebKit added the API as part of the original Selectors API Level 1 work, so every Safari since Safari 3.1 on Mac OS X 10.5 Leopard ships the method without a flag, including Safari 18 on Sequoia.
Safari on iOS and iPadOS supports querySelector from iOS 3.2 on iPhone and iPad. Apple's WebKit-only rule means Chrome, Edge, Firefox, and every other browser on iOS pick up the same WebKit-shipped implementation, so support is consistent across the entire iOS browser fleet.
Opera supports querySelector from Opera 10 on Windows, macOS, Linux, and Android. Opera 9 to 9.6 had no native support, and the modern Chromium-based Opera 15+ ships the same Blink implementation as Chrome. Opera Mobile 10+ and Opera Mini support it on Android.
Samsung Internet supports querySelector from Samsung Internet 4 on Galaxy phones running Android 4.4 KitKat or later. Every Samsung Internet release since then ships the method through the Chromium pipeline that Chrome for Android also uses.
The legacy stock Android Browser supports querySelector from Android 2.1 Eclair. Chrome for Android, the modern WebView, Samsung Internet, and Firefox for Android also support the method on every supported Android version, so the API is universal across the Android browser stack.
Internet Explorer supports querySelector from Internet Explorer 9 on Windows Vista, 7, 8, 8.1, and 10. Internet Explorer 8 has partial support and only matches CSS 2.1 selectors, while IE 5.5 to 7 do not support the API at all. Microsoft has retired Internet Explorer, so move querySelector-dependent apps to Chromium-based Edge.
Note: querySelector behavior shifts across CSS selector grammars, IE 8 partial support, and shadow-DOM scoping. Test it on real browsers and OS with TestMu AI. Try TestMu AI free!
querySelector takes one argument, a string of one or more CSS selectors, and returns the first matching Element or null when nothing matches. The method runs a depth-first, pre-order walk of the document, so the first element in source order wins. The same signature is exposed on document, on any Element instance, and on DocumentFragment for shadow-DOM scoping.
querySelector accepts every CSS selector the parser understands. Class selectors like .card, ID selectors like #login, attribute selectors like input[name='email'], compound selectors like .card.active, descendant selectors like form input, and selector lists like h1, h2, h3 all work. Pseudo-classes like :not, :is, :has, :nth-child, and :focus-visible match the live state of the DOM at call time.
Paste this snippet into the DevTools console of any modern browser. The console logs the first paragraph, the first email input, the first active card, the first heading, and a null for a selector that does not match anything on the page.
// Paste this into the DevTools console of any modern browser.
if ("querySelector" in document) {
console.log("querySelector is available.");
const firstParagraph = document.querySelector("p");
console.log("First paragraph element:", firstParagraph);
const emailInput = document.querySelector("form input[name='email']");
console.log("Email input:", emailInput);
// AND logic: an element with both classes
const activeCard = document.querySelector(".card.active");
console.log("Active card:", activeCard);
// OR logic: the first heading of any level
const heading = document.querySelector("h1, h2, h3");
console.log("First heading:", heading);
// Miss returns null, not undefined
const missing = document.querySelector(".not-on-this-page");
console.log("Missing element returns:", missing);
} else {
console.log("querySelector is not supported in this browser.");
}querySelector is the most common entry point for picking a single element out of the DOM, and modern frameworks, test runners, and bookmarklets all lean on it. Production apps use it for forms, single-page-app routing, dialog management, web components, and analytics tagging.
querySelector returns one element, querySelectorAll returns a NodeList of every match, and getElementById finds a single element by its id only. Each call has a different return type, selector grammar, and performance profile, so the right pick depends on the shape of the lookup.
| Dimension | querySelector | querySelectorAll | getElementById |
|---|---|---|---|
| Selector input | Any CSS selector string | Any CSS selector string | A single id string |
| Return value | Element or null | Static NodeList | Element or null |
| Multiple matches | First match only | Every match in source order | One element, since the id should be unique |
| Performance | Selector walk over the subtree | Selector walk over the subtree | Internal hash-table lookup |
| Browser since | Chrome 4, Firefox 3.5, IE 9 | Chrome 4, Firefox 3.5, IE 9 | Every browser since IE 5.5 |
| Best fit | Single complex CSS lookup | Iterating every match | Hot-path id lookup |
querySelector is universally supported, so the rough edges show up in selector grammar, return-value gotchas, and old-IE behavior rather than browser gaps.
In my experience, the trap that bites every querySelector integration once is the null-on-miss contract. A page renders fine in development, then the script breaks in production because a CSS class got renamed and the script tried to read .style on null. Wrap every call in optional chaining or a null check and the entire class of bugs disappears.
All querySelector version numbers and platform notes in this guide come from these primary sources:
Did you find this page helpful?
More Related Hubs
TestMu AI forEnterprise
Get access to solutions built on Enterprise
grade security, privacy, & compliance