XPath Basics
Learn XPath fundamentals for locating elements when CSS selectors aren't enough.
Selenium 3 & 4 Medium
XPath (XML Path Language) is a powerful query language for selecting elements in HTML/XML documents. While CSS selectors are often preferred for their simplicity, XPath offers capabilities that CSS cannot match. For a comprehensive XPath tutorial, check out our sister site XPath Decoded.
When to Use XPath
Use XPath when you need to:
- Navigate up the DOM tree (to parent elements)
- Find elements by their text content
- Use complex conditions combining multiple attributes
- Navigate sibling relationships
Basic XPath Syntax
| Expression | Description |
|---|---|
// | Select from anywhere in document |
/ | Select from root/current element |
[@attr] | Element with attribute |
[@attr='value'] | Attribute equals value |
text() | Text content of element |
. | Current element |
.. | Parent element |
Finding Elements by Attribute
XPath Attribute Selectors
Selenium 3 & 4 Stable
import org.openqa.selenium.By;import org.openqa.selenium.WebElement;
// By ID (equivalent to By.id())WebElement byId = driver.findElement(By.xpath("//*[@id='username']"));
// By class (single class)WebElement byClass = driver.findElement(By.xpath("//*[@class='btn-primary']"));
// By any attributeWebElement byDataId = driver.findElement(By.xpath("//*[@data-testid='submit']"));
// By attribute containing valueWebElement contains = driver.findElement( By.xpath("//*[contains(@class, 'btn')]"));
// By attribute starting with valueWebElement startsWith = driver.findElement( By.xpath("//*[starts-with(@id, 'user-')]"));
// Multiple attributesWebElement multiAttr = driver.findElement( By.xpath("//input[@type='text'][@name='email']"));from selenium.webdriver.common.by import By
# By ID (equivalent to By.ID)by_id = driver.find_element(By.XPATH, "//*[@id='username']")
# By class (single class)by_class = driver.find_element(By.XPATH, "//*[@class='btn-primary']")
# By any attributeby_data_id = driver.find_element(By.XPATH, "//*[@data-testid='submit']")
# By attribute containing valuecontains = driver.find_element( By.XPATH, "//*[contains(@class, 'btn')]")
# By attribute starting with valuestarts_with = driver.find_element( By.XPATH, "//*[starts-with(@id, 'user-')]")
# Multiple attributesmulti_attr = driver.find_element( By.XPATH, "//input[@type='text'][@name='email']")const { By } = require('selenium-webdriver');
// By ID (equivalent to By.id())const byId = await driver.findElement(By.xpath("//*[@id='username']"));
// By class (single class)const byClass = await driver.findElement(By.xpath("//*[@class='btn-primary']"));
// By any attributeconst byDataId = await driver.findElement(By.xpath("//*[@data-testid='submit']"));
// By attribute containing valueconst contains = await driver.findElement( By.xpath("//*[contains(@class, 'btn')]"));
// By attribute starting with valueconst startsWith = await driver.findElement( By.xpath("//*[starts-with(@id, 'user-')]"));
// Multiple attributesconst multiAttr = await driver.findElement( By.xpath("//input[@type='text'][@name='email']"));using OpenQA.Selenium;
// By ID (equivalent to By.Id())IWebElement byId = driver.FindElement(By.XPath("//*[@id='username']"));
// By class (single class)IWebElement byClass = driver.FindElement(By.XPath("//*[@class='btn-primary']"));
// By any attributeIWebElement byDataId = driver.FindElement(By.XPath("//*[@data-testid='submit']"));
// By attribute containing valueIWebElement contains = driver.FindElement( By.XPath("//*[contains(@class, 'btn')]"));
// By attribute starting with valueIWebElement startsWith = driver.FindElement( By.XPath("//*[starts-with(@id, 'user-')]"));
// Multiple attributesIWebElement multiAttr = driver.FindElement( By.XPath("//input[@type='text'][@name='email']"));Finding Elements by Text
One of XPath’s unique capabilities is finding elements by their visible text:
XPath Text Selectors
Selenium 3 & 4 Medium
// Exact text matchWebElement exactText = driver.findElement( By.xpath("//button[text()='Submit']"));
// Contains text (partial match)WebElement containsText = driver.findElement( By.xpath("//button[contains(text(), 'Sub')]"));
// Normalize whitespace and matchWebElement normalizedText = driver.findElement( By.xpath("//button[normalize-space(text())='Submit Form']"));
// Find link by textWebElement linkByText = driver.findElement( By.xpath("//a[text()='Click Here']"));
// Text anywhere in element (including children)WebElement deepText = driver.findElement( By.xpath("//div[contains(., 'Welcome')]"));# Exact text matchexact_text = driver.find_element( By.XPATH, "//button[text()='Submit']")
# Contains text (partial match)contains_text = driver.find_element( By.XPATH, "//button[contains(text(), 'Sub')]")
# Normalize whitespace and matchnormalized_text = driver.find_element( By.XPATH, "//button[normalize-space(text())='Submit Form']")
# Find link by textlink_by_text = driver.find_element( By.XPATH, "//a[text()='Click Here']")
# Text anywhere in element (including children)deep_text = driver.find_element( By.XPATH, "//div[contains(., 'Welcome')]")// Exact text matchconst exactText = await driver.findElement( By.xpath("//button[text()='Submit']"));
// Contains text (partial match)const containsText = await driver.findElement( By.xpath("//button[contains(text(), 'Sub')]"));
// Normalize whitespace and matchconst normalizedText = await driver.findElement( By.xpath("//button[normalize-space(text())='Submit Form']"));
// Find link by textconst linkByText = await driver.findElement( By.xpath("//a[text()='Click Here']"));
// Text anywhere in element (including children)const deepText = await driver.findElement( By.xpath("//div[contains(., 'Welcome')]"));// Exact text matchIWebElement exactText = driver.FindElement( By.XPath("//button[text()='Submit']"));
// Contains text (partial match)IWebElement containsText = driver.FindElement( By.XPath("//button[contains(text(), 'Sub')]"));
// Normalize whitespace and matchIWebElement normalizedText = driver.FindElement( By.XPath("//button[normalize-space(text())='Submit Form']"));
// Find link by textIWebElement linkByText = driver.FindElement( By.XPath("//a[text()='Click Here']"));
// Text anywhere in element (including children)IWebElement deepText = driver.FindElement( By.XPath("//div[contains(., 'Welcome')]"));Navigating the DOM
XPath excels at navigating relationships between elements:
XPath Navigation
Selenium 3 & 4 Medium
// Parent element// From <span> find parent <div>WebElement parent = driver.findElement( By.xpath("//span[@class='error']/parent::div"));
// Alternative parent syntaxWebElement parentAlt = driver.findElement( By.xpath("//span[@class='error']/.."));
// Ancestor (any level up)WebElement ancestor = driver.findElement( By.xpath("//span[@class='error']/ancestor::form"));
// Child elementsWebElement child = driver.findElement( By.xpath("//ul[@id='menu']/child::li"));
// Following siblingWebElement nextSibling = driver.findElement( By.xpath("//label[text()='Email']/following-sibling::input"));
// Preceding siblingWebElement prevSibling = driver.findElement( By.xpath("//input[@id='email']/preceding-sibling::label"));
// Descendant (any level down)WebElement descendant = driver.findElement( By.xpath("//div[@id='container']/descendant::button"));# Parent element# From <span> find parent <div>parent = driver.find_element( By.XPATH, "//span[@class='error']/parent::div")
# Alternative parent syntaxparent_alt = driver.find_element( By.XPATH, "//span[@class='error']/..")
# Ancestor (any level up)ancestor = driver.find_element( By.XPATH, "//span[@class='error']/ancestor::form")
# Child elementschild = driver.find_element( By.XPATH, "//ul[@id='menu']/child::li")
# Following siblingnext_sibling = driver.find_element( By.XPATH, "//label[text()='Email']/following-sibling::input")
# Preceding siblingprev_sibling = driver.find_element( By.XPATH, "//input[@id='email']/preceding-sibling::label")
# Descendant (any level down)descendant = driver.find_element( By.XPATH, "//div[@id='container']/descendant::button")// Parent element// From <span> find parent <div>const parent = await driver.findElement( By.xpath("//span[@class='error']/parent::div"));
// Alternative parent syntaxconst parentAlt = await driver.findElement( By.xpath("//span[@class='error']/.."));
// Ancestor (any level up)const ancestor = await driver.findElement( By.xpath("//span[@class='error']/ancestor::form"));
// Child elementsconst child = await driver.findElement( By.xpath("//ul[@id='menu']/child::li"));
// Following siblingconst nextSibling = await driver.findElement( By.xpath("//label[text()='Email']/following-sibling::input"));
// Preceding siblingconst prevSibling = await driver.findElement( By.xpath("//input[@id='email']/preceding-sibling::label"));
// Descendant (any level down)const descendant = await driver.findElement( By.xpath("//div[@id='container']/descendant::button"));// Parent element// From <span> find parent <div>IWebElement parent = driver.FindElement( By.XPath("//span[@class='error']/parent::div"));
// Alternative parent syntaxIWebElement parentAlt = driver.FindElement( By.XPath("//span[@class='error']/.."));
// Ancestor (any level up)IWebElement ancestor = driver.FindElement( By.XPath("//span[@class='error']/ancestor::form"));
// Child elementsIWebElement child = driver.FindElement( By.XPath("//ul[@id='menu']/child::li"));
// Following siblingIWebElement nextSibling = driver.FindElement( By.XPath("//label[text()='Email']/following-sibling::input"));
// Preceding siblingIWebElement prevSibling = driver.FindElement( By.XPath("//input[@id='email']/preceding-sibling::label"));
// Descendant (any level down)IWebElement descendant = driver.FindElement( By.XPath("//div[@id='container']/descendant::button"));Position-Based Selection
XPath allows selecting elements by their position:
XPath Positional Selection
Selenium 3 & 4 Fragile
// First item (XPath is 1-indexed!)WebElement first = driver.findElement(By.xpath("//ul/li[1]"));
// Last itemWebElement last = driver.findElement(By.xpath("//ul/li[last()]"));
// Second to lastWebElement secondLast = driver.findElement(By.xpath("//ul/li[last()-1]"));
// First 3 itemsList<WebElement> firstThree = driver.findElements( By.xpath("//ul/li[position() <= 3]"));
// Odd positioned itemsList<WebElement> oddItems = driver.findElements( By.xpath("//ul/li[position() mod 2 = 1]"));
// Nth child of specific typeWebElement thirdButton = driver.findElement( By.xpath("(//button[@class='action'])[3]"));# First item (XPath is 1-indexed!)first = driver.find_element(By.XPATH, "//ul/li[1]")
# Last itemlast = driver.find_element(By.XPATH, "//ul/li[last()]")
# Second to lastsecond_last = driver.find_element(By.XPATH, "//ul/li[last()-1]")
# First 3 itemsfirst_three = driver.find_elements( By.XPATH, "//ul/li[position() <= 3]")
# Odd positioned itemsodd_items = driver.find_elements( By.XPATH, "//ul/li[position() mod 2 = 1]")
# Nth child of specific typethird_button = driver.find_element( By.XPATH, "(//button[@class='action'])[3]")// First item (XPath is 1-indexed!)const first = await driver.findElement(By.xpath('//ul/li[1]'));
// Last itemconst last = await driver.findElement(By.xpath('//ul/li[last()]'));
// Second to lastconst secondLast = await driver.findElement(By.xpath('//ul/li[last()-1]'));
// First 3 itemsconst firstThree = await driver.findElements( By.xpath('//ul/li[position() <= 3]'));
// Odd positioned itemsconst oddItems = await driver.findElements( By.xpath('//ul/li[position() mod 2 = 1]'));
// Nth child of specific typeconst thirdButton = await driver.findElement( By.xpath("(//button[@class='action'])[3]"));// First item (XPath is 1-indexed!)IWebElement first = driver.FindElement(By.XPath("//ul/li[1]"));
// Last itemIWebElement last = driver.FindElement(By.XPath("//ul/li[last()]"));
// Second to lastIWebElement secondLast = driver.FindElement(By.XPath("//ul/li[last()-1]"));
// First 3 itemsIList<IWebElement> firstThree = driver.FindElements( By.XPath("//ul/li[position() <= 3]"));
// Odd positioned itemsIList<IWebElement> oddItems = driver.FindElements( By.XPath("//ul/li[position() mod 2 = 1]"));
// Nth child of specific typeIWebElement thirdButton = driver.FindElement( By.XPath("(//button[@class='action'])[3]"));Warning: Position-based locators are fragile. Use them only when necessary and prefer more stable alternatives.
XPath Functions
| Function | Description | Example |
|---|---|---|
contains() | Partial match | contains(@class, 'btn') |
starts-with() | Begins with | starts-with(@id, 'item-') |
text() | Element text | text()='Submit' |
normalize-space() | Trim whitespace | normalize-space(text())='Hello' |
not() | Negation | not(@disabled) |
and / or | Boolean logic | @type='text' and @name='email' |
XPath vs CSS Selectors
| Feature | CSS | XPath |
|---|---|---|
| Performance | Faster | Slightly slower |
| Text content | Not supported | Supported |
| Parent traversal | Not supported | Supported |
| Sibling navigation | Limited | Full support |
| Readability | More readable | Can be complex |
| Browser support | Excellent | Excellent |
Best Practices
- Prefer CSS for simple selections
- Use XPath when you need text-based or parent/sibling navigation
- Avoid position unless absolutely necessary
- Keep paths short - long XPath expressions are fragile
- Use contains() for partial class matches instead of exact matches
Next Steps
- XPath Advanced - Complex XPath techniques
- Relative Locators - Selenium 4’s spatial locators
- CSS Selectors - Compare with CSS approaches
- XPath Decoded - Master XPath with interactive examples