DEV Community

Weather Clock Dash
Weather Clock Dash

Posted on

XPath in Firefox: $x() in DevTools, Selenium/Playwright, JavaScript document.evaluate, and Extension Usage

XPath (XML Path Language) is a powerful query language for selecting nodes in an XML/HTML document. While CSS selectors are simpler and more commonly used in web development, XPath is more expressive and is essential for certain use cases: test automation, web scraping, browser extensions, and XML processing. Firefox has excellent XPath support, including in DevTools.

XPath vs. CSS Selectors

CSS selectors are better for:

  • Most styling and DOM manipulation tasks
  • When you only need to go "down" the tree (parent → child)
  • Modern web development with querySelector

XPath is better for:

  • Selecting a parent based on its child (CSS can't do this)
  • Text content matching
  • Complex positional logic (last, position, preceding-sibling)
  • More expressive queries in test automation

Basic XPath Syntax

/html/body/div                # Absolute path from root
//div                         # Select all divs anywhere
//div[@class='container']     # With attribute
//div[@id='main']             # By ID
//*[@class='btn']             # Any element with class 'btn'
//p[1]                        # First paragraph
//p[last()]                   # Last paragraph
//p[position() > 2]           # Paragraphs after position 2
Enter fullscreen mode Exit fullscreen mode

XPath in Firefox DevTools

Method 1: Console

Firefox's DevTools console supports $x() (Chrome has it too but Firefox accepts more XPath 1.0 syntax):

// Select all elements matching XPath
$x('//div[@class="highlight"]')

// Get text content of matching elements
$x('//h2/text()')

// Find parent of element with specific child
$x('//ul[li[@class="active"]]')
Enter fullscreen mode Exit fullscreen mode

$x() returns an array of matching nodes, just like $$() for CSS selectors.

Method 2: Inspector search

In the Inspector panel, press Ctrl+F to open the search bar. Firefox's search supports XPath — type an XPath expression starting with / or // and it will search using XPath:

//button[contains(@class, 'primary')]
//input[@type='submit']
//*[text()='Submit']
Enter fullscreen mode Exit fullscreen mode

Matches are highlighted and counted in the HTML panel.

Useful XPath Patterns

Text content matching

//h1[text()='Welcome']              # Exact match
//p[contains(text(), 'Firefox')]    # Contains
//a[starts-with(text(), 'Read')]    # Starts with
Enter fullscreen mode Exit fullscreen mode

Multiple conditions (AND/OR)

//div[@class='card' and @data-type='user']
//button[@type='submit' or @type='button']
Enter fullscreen mode Exit fullscreen mode

Traversing up the tree (what CSS can't do)

//input[@name='email']/..           # Parent of email input
//span[@class='error']/../..        # Grandparent of error span
//td[text()='Active']/../..         # Row containing 'Active' cell
Enter fullscreen mode Exit fullscreen mode

Sibling selection

//h2[text()='Features']/following-sibling::ul[1]  # First list after 'Features' heading
//li[@class='active']/preceding-sibling::li[1]     # Previous sibling of active item
Enter fullscreen mode Exit fullscreen mode

Positional

//table/tbody/tr[last()]             # Last row
//table/tbody/tr[position() <= 5]    # First 5 rows
(//div[@class='item'])[3]            # Third item (note extra parens)
Enter fullscreen mode Exit fullscreen mode

XPath in Selenium/Playwright for Test Automation

XPath is widely used in Selenium because CSS can't select by text content or traverse up:

# Selenium (Python)
from selenium.webdriver.common.by import By

driver.find_element(By.XPATH, '//button[contains(text(), "Submit")]')
driver.find_element(By.XPATH, '//label[text()="Email"]/following-sibling::input')
Enter fullscreen mode Exit fullscreen mode
// Playwright
const button = await page.locator('xpath=//button[contains(text(), "Submit")]');
await button.click();

// Playwright prefers text locators over XPath where possible:
const button2 = await page.getByText('Submit');
Enter fullscreen mode Exit fullscreen mode

Playwright's recommendation is to prefer text, role, and accessibility locators over XPath/CSS where possible. But XPath is still useful for:

  • Legacy test suites
  • Finding elements by complex structural relationships
  • Third-party HTML you don't control

XPath in JavaScript

The native DOM API has full XPath support:

// document.evaluate(expression, contextNode, namespaceResolver, resultType, result)

// Single result
const result = document.evaluate(
  '//h1[contains(text(), "Firefox")]',
  document,
  null,
  XPathResult.FIRST_ORDERED_NODE_TYPE,
  null
);
const element = result.singleNodeValue;

// Multiple results
const results = document.evaluate(
  '//a[@href]',
  document,
  null,
  XPathResult.ORDERED_NODE_ITERATOR_TYPE,
  null
);
let node;
while ((node = results.iterateNext())) {
  console.log(node.href);
}
Enter fullscreen mode Exit fullscreen mode

The $x() shorthand in DevTools is just a wrapper around document.evaluate().

XPath in Firefox Extensions (WebExtensions)

Browser extensions can use XPath via content scripts:

// content script
function findByXPath(xpath) {
  return document.evaluate(
    xpath,
    document,
    null,
    XPathResult.ORDERED_NODE_ARRAY_TYPE,
    null
  ).singleNodeValue;
}
Enter fullscreen mode Exit fullscreen mode

Useful for extensions that inject UI relative to specific page elements, or for content manipulation extensions.

XPath Namespaces in SVG/XML

For SVG or custom XML namespaces:

function nsResolver(prefix) {
  const namespaces = {
    'svg': 'http://www.w3.org/2000/svg',
    'xhtml': 'http://www.w3.org/1999/xhtml'
  };
  return namespaces[prefix] || null;
}

document.evaluate(
  '//svg:circle[@r > 10]',
  document,
  nsResolver,
  XPathResult.ORDERED_NODE_ITERATOR_TYPE,
  null
);
Enter fullscreen mode Exit fullscreen mode

Common XPath Gotchas

Class attributes: XPath's @class='btn' requires an exact match. For partial class matching, use contains(@class, 'btn').

XPath 1.0 only: browsers implement XPath 1.0, which lacks some features from XPath 2.0/3.0 (like sequence functions). $x() in DevTools uses 1.0.

Performance: complex XPath expressions that traverse the entire document can be slow on large DOMs. Prefer specificity (start from a specific context node, not // from the root when possible).

HTML case sensitivity: HTML attributes are case-insensitive in HTML but XPath is case-sensitive. @CLASS and @class are different. Test @class, not @CLASS.

Top comments (0)