By Tim King · Updated
CSS Selector Tester
Matched Element Paths, Attributes and Text From Pasted HTML
OneTask is free, with no sign-up, and built by one person.
If this tool saved you time, a coffee helps keep new ones coming.
How the CSS Selector Tester works
This CSS selector tester highlights every element a selector matches. Paste a fragment of HTML or a whole page, write a CSS selector and see exactly which elements it picks out. Every match is listed with a unique path, its tag and classes, and either its markup, its text or its attributes, so you can check a scraper, a test locator or a stylesheet rule before you rely on it.
CSS selector tester: specificity and matching
CSS selectors are how stylesheets, JavaScript, scrapers and end-to-end tests all point at
elements. The same string works in a .css file, in document.querySelectorAll, in
BeautifulSoup's select(), in Playwright and Cypress locators and in Scrapy. Because the syntax
is compact, it is easy to write a selector that is subtly too broad — matching a hidden
duplicate of the element — or too narrow, matching nothing on the page you actually get from
the server. This tester evaluates the selector with the browser's own engine, so the result is
authoritative.
Simple selectors. div by tag, .price by class, #main by id, [data-id] by attribute
presence and [href^="https"] by attribute value with the ^= starts-with, $= ends-with,
*= contains and ~= word-in-list operators. Combine them without spaces to require all of
them on one element: a.button[target=_blank].
Combinators. A space means descendant at any depth, > means direct child, + the
immediately following sibling and ~ any later sibling. nav > ul > li walks a fixed
structure; h2 + p finds the paragraph directly after each heading. Comma separates
alternatives: h1, h2, h3 matches all three.
Pseudo-classes. :first-child, :last-child, :nth-child(2n+1), :nth-of-type(3),
:not(.hidden), :has(img), :is(article, section) > h2, :empty and :checked are all
supported by modern browsers and therefore by this tool. :has() in particular lets a selector
choose a parent based on its children, which was impossible in CSS for years and is now the
standard answer to "the card that contains a sold-out badge".
What is not supported. Pseudo-elements like ::before do not select elements and cannot be
queried. Interaction states — :hover, :focus, :visited — never match in a static document.
Library extensions such as jQuery's :contains() and :eq() are not real CSS and will report a
syntax error; use :has() or an XPath expression instead.
Reading the results. Each match gets a path of the form body > div:nth-child(2) > a that
identifies it uniquely and can be pasted straight back in. The Show setting switches the right
column between the element's outer HTML, its trimmed text and a list of its attributes.
The headline count is the fastest sanity check: a scraper selector should usually match exactly
the number of items you can see on the page.
Parsing. The text is parsed with the browser's HTML parser, so fragments without html or
body wrappers are fine, unclosed tags are repaired the way a browser would repair them, and
element names are case-insensitive. Scripts in the pasted HTML are never executed.
FAQ
Why does a selector that works in DevTools match nothing here?
DevTools runs against the live DOM after JavaScript has run. If the elements you see are
rendered by a framework, they are not in the server's HTML. Paste the DOM from the Elements
panel — right-click html, Copy outerHTML — rather than the page source.
Does it support :has() and :is()?
Yes, along with :where(), :not() with complex arguments, and the :nth-child(An+B of S)
form, because it uses the browser's selector engine and every current browser supports them. If
your target is an older scraping library, check that library's documentation before relying on
them.
How do I select by text content?
CSS cannot. Selecting by the text an element contains is a job for XPath — //a[contains(., 'Next')] — or for a test framework's text locator. Use the XPath tester for that, or select a
structural parent here and filter in code.
Why do I get duplicate matches?
querySelectorAll returns each element once, so real duplicates mean the page really has two
copies — typically a mobile and a desktop version of the same component, one hidden by CSS. Add
:not([hidden]) or narrow by an ancestor to pick the one you want.
See also: all Dev Utilities tools, Formatters & Validators, Data & Encoding, Security & Identifiers, SEO, Accessibility, AI.
Related tools
CHMOD Calculator
Convert Unix permissions between rwx, octal and symbolic.
Core Web Vitals Calculator
Check whether your page passes Core Web Vitals and which metric to fix first.
DNS Lookup
Query any DNS record for a domain with TTLs and explanations.
HTTP Status Codes
Look up what any HTTP status code actually means.
IP Address Info
Classify any IPv4 or IPv6 address and see its every form.