Page under test
XPath

    Challenges

      XPath cheat sheet

      Every example below works in the playground above. Prefer relative paths that start with // over absolute ones like /html/body/main/ul/li[2]: an absolute path breaks the moment the page layout changes.

      ExpressionWhat it selects
      //h1Every h1 element, anywhere on the page.
      //input[@id='nl-email']An element by an exact attribute value.
      //button[text()='Subscribe']An element whose own text is exactly "Subscribe".
      //h2[contains(text(),'Key')]Partial text match.
      //li[contains(@class,'sale')]One class among several (@class='sale' fails when there are more classes).
      //label[normalize-space()='Email address']Text match that ignores extra spaces and line breaks.
      //input[@type='checkbox' and @name='terms']Combine conditions with and / or.
      //h2/following-sibling::spanSiblings that come after an element.
      //td[text()='#1002']/parent::trStep up to the parent.
      //span[text()='Shipped']/ancestor::trStep up any number of levels to an ancestor.
      //tr[td[text()='#1002']]A row that contains a matching cell, without stepping back up.
      (//li)[2]The second match on the whole page.
      //ul/li[2]The second li inside each ul. Not the same as (//li)[2].
      //*[starts-with(@data-testid,'add-')]Attribute starts with a prefix, on any element type.

      XPath or CSS?

      Reach for XPath when you need to match on text or walk up the tree (parent::, ancestor::), which CSS can't do. For everything else, CSS is shorter and usually faster. Try the same tasks in the CSS Selector Playground, or see how Playwright's user-facing locators compare in the Playwright Locator Playground.