XPath & CSS Selector Tester

Test CSS selectors and XPath on your own HTML and see every match as text. The HTML is never rendered, its scripts never run, and it never leaves your browser.

The HTML you paste is parsed into an inert document: it is never shown as a page, its scripts never run and nothing it links to is loaded. Results appear as text only.

Query type

CSS selectors and XPath 1.0, run by your browser on the parsed document.

0 characters

Files up to 5 MB are read on your device and never uploaded.

Paste HTML and type a selector. Nothing you enter leaves your browser.

Matches

    Common test-automation selectors

    Each loads a small sample and its query into the tool.

    • CSS #email → 1 match
    • CSS [data-testid="save"] → 1 match, first “Save”
    • XPath //button[contains(., 'Sign in')] → 1 match, first “Sign in”
    • CSS a[href^="https://example.com/docs/"] → 2 matches, first “A”
    • CSS table > tbody > tr:nth-child(2) → 1 match, first “Bo”
    • XPath //input[@id = //label[normalize-space()='Email']/@for] → 1 match

    Quick reference

    The examples run on this sample: a page with a nav, a heading, a table, a list and a form. Load it with the button.

    CSS selectors

    SyntaxMeaningExample on the sample → result
    tagElements with this tagli → 3 matches, first “First”
    #idThe element with this id#orders → 1 match, first “Orders”
    .classElements with this class.done → 1 match, first “Second”
    [attr]Elements that have the attribute[required] → 1 match
    [attr="v"]The attribute equals v[name="email"] → 1 match
    [attr^="v"]The attribute starts with va[href^="https://example.com/docs"] → 1 match, first “Docs”
    [attr$="v"]The attribute ends with va[href$="/help"] → 1 match, first “Help”
    [attr*="v"]The attribute contains v[href*="example"] → 2 matches, first “Docs”
    A BB anywhere inside Anav a → 2 matches, first “Docs”
    A > BB directly inside Aul > li → 3 matches, first “First”
    A + BThe B right after Ah2 + p → 1 match, first “Two open orders.”
    A ~ BEvery B after A, same parentlabel ~ input → 2 matches
    :nth-child(n)The n-th child of its parentli:nth-child(2) → 1 match, first “Second”
    :nth-of-type(n)The n-th of its tag among its siblingstr:nth-of-type(3) > td → 2 matches, first “B-2”
    :first-childThe first child of its parentli:first-child → 1 match, first “First”
    :not(…)Elements that don't matchli:not(.done) → 2 matches, first “First”
    :checkedTicked checkboxes and chosen optionsinput:checked → 1 match
    :disabledDisabled form controlsbutton:disabled → 1 match, first “Send”
    :has(…)Elements containing a match (depending on your browser)tr:has(td) → 2 matches, first “A-1Open”

    XPath 1.0

    SyntaxMeaningExample on the sample → result
    //tagElements with this tag, anywhere//li → 3 matches, first “First”
    /a/bA path from the root/html/body/h2 → 1 match, first “Orders”
    [@id='…']An attribute condition//*[@id='orders'] → 1 match, first “Orders”
    [@attr]Elements that have the attribute//input[@required] → 1 match
    /@attrThe attribute nodes themselves//a/@href → 2 matches, first “https://example.com/docs/start”
    [n]The n-th of its siblings (from 1)//li[2] → 1 match, first “Second”
    [last()]The last one//li[last()] → 1 match, first “Third”
    text()Text nodes//h2/text() → 1 match, first “Orders”
    [.='…']Elements whose text equals …//li[.='Third'] → 1 match, first “Third”
    contains()Text or attribute contains …//p[contains(., 'open')] → 1 match, first “Two open orders.”
    starts-with()Starts with …//a[starts-with(@href, 'https://example.com/docs')] → 1 match, first “Docs”
    ..The parent//td[.='A-1']/.. → 1 match, first “A-1Open”
    following-sibling::Later siblings//label/following-sibling::input[1] → 1 match
    preceding-sibling::Earlier siblings//li[.='Third']/preceding-sibling::li → 2 matches, first “First”
    ancestor::Any ancestor//button/ancestor::form → 1 match, first “Email Send”
    normalize-space()Text with spaces tidied//button[normalize-space()='Send'] → 1 match, first “Send”
    A | BBoth sets, in document order//h2 | //p → 2 matches, first “Orders”
    count()A numbercount(//tr) → number 3
    string()A stringstring(//title) → string Orders
    boolean()True or falseboolean(//form[@id='f']) → boolean true

    A CSS selector, such as “#email” or “[data-testid="save"]”, picks elements by tag, id, class, attributes and position. XPath is a path language that can also walk up to parents and match by text, as in “//button[contains(., 'Sign in')]”. Test-automation tools use both to find the element to click or check.

    How the tool evaluates

    The HTML is parsed by your browser's own HTML parser into an inert document: it is never shown as a page, its scripts never run, and nothing it links to is loaded. Queries run on that parsed tree, not on the source text, and the two can differ. The parser adds a tbody to tables and corrects broken markup, so “table > tbody > tr” matches a table whose source has no tbody. That tree is what your test really sees.

    A match is marked in the source view only when one of its attributes appears there exactly once; otherwise it is only listed.

    CSS or XPath?

    CSS selectors are shorter, usually faster, and supported by every test framework. XPath can do what CSS can't: go up from a match, as in “//button/ancestor::form”, or find an element by its text. Browsers implement XPath 1.0, which has no regular expressions.

    Stable selectors

    Prefer an id or a test attribute such as data-testid over long paths and positions: “#email” survives a redesign that breaks a positional path. The suggestions under the matches follow that order and flag the fragile ones, but a suggestion is only as stable as the page. RoboQA, which makes these tools, lets you describe a test in plain English instead of writing selectors.

    XML and namespaces

    With “Treat input as XML”, the input is parsed as XML and parse errors are reported. XPath 1.0 has no default namespace, so in a document whose elements are in a namespace, “//item” finds nothing: map a prefix to the namespace URI in the prefix map and write “//p:item”.

    Limits and privacy

    The HTML can be up to 1,000,000 characters and the query up to 5,000; the list shows the first 500 matches with the real total. Above 200,000 characters, queries run only when you press Run. A pathological query on a huge document can freeze the page, and it can't be stopped once started. Your HTML never leaves your browser. Like the rest of the site, the page records a visit when it loads, but not what you paste.

    How to use

    1. Paste HTML, load a file or load the sample, then choose CSS selector or XPath.
    2. Type a query; the matches appear as you type, with their paths, attributes and text.
    3. Use a suggested selector, or copy the matches or the query.

    Features

    Common uses

    Frequently asked questions

    How do I test an XPath online?

    Paste the HTML, choose XPath and type the expression. Nodes are listed with their paths, and expressions such as count() or string() show their value and type.

    How do I test a CSS selector?

    Paste the HTML, choose CSS selector and type it; the count and matches appear as you type.

    What is the difference between XPath and CSS selectors?

    Both find elements. CSS is shorter and supported everywhere; XPath can also go up to parents and select by text.

    Why doesn't my selector match the element I see in the source?

    Queries run on the parsed tree, which can differ from the source: the parser adds tbody, moves misplaced elements and fixes broken tags. Content that scripts add later isn't there at all, because scripts never run here.

    What is XPath 1.0 and what does it lack?

    The XPath version browsers implement. It has no regular expressions, no lower-case() or ends-with() and no default namespace; those arrived with XPath 2.0.

    Why is my XPath with a namespace empty?

    In XPath 1.0 an element in a namespace needs a prefix in the query. Tick “Treat input as XML”, map a prefix to the namespace URI and use it, as in “//p:item”.

    Is my HTML uploaded?

    No. It is parsed and queried in your browser and never sent anywhere or saved. The page itself records a visit when it loads, as every page here does.

    Is it safe to paste a page with scripts?

    This tool never runs them: the HTML goes into an inert document, nothing it links to is loaded, and results are shown as text. Still treat pages from unknown sources with care.

    Need to test a whole website, not just a snippet?

    RoboQA tests real pages and user journeys in a browser: logins, forms, clicks and full flows. See what RoboQA can test or compare plans.

    More free tools

    See all free tools