
Ever struggled to select a deeply nested element in Cypress when CSS selectors just don’t seem flexible enough?
While Cypress primarily promotes CSS-based selectors, there are scenarios where navigating complex DOM relationships or selecting elements by text becomes easier with XPath.
This is where Cypress XPath comes into play. By adding XPath support through a plugin, you can write more expressive queries for specific use cases without changing your core Cypress workflow.
This article explores what Cypress XPath is, when to use it, and how to implement it effectively in your test automation strategy.
XPath (XML Path Language) is a query language used to navigate and select elements from an XML or HTML document. In the context of Cypress, XPath allows testers to locate elements using structured path expressions instead of traditional CSS selectors.
By default, Cypress does not support XPath. It is designed to work primarily with CSS-based selectors through commands like cy.get(). However, XPath support can be added using a plugin (such as cypress-xpath), which introduces the cy.xpath() command for locating elements.
Once enabled, XPath allows you to:
For example:
cy.xpath("//button[text()='Submit']").click()
Here, the XPath expression selects a button element based on its visible text.
In short, XPath in Cypress is an optional selector strategy that expands how you can locate elements, particularly in complex DOM structures, while still leveraging Cypress’s built-in test execution and retry capabilities.
While Cypress primarily encourages CSS selectors, there are situations where XPath offers more flexibility, especially when dealing with complex or dynamic DOM structures. XPath can be a practical alternative when CSS selectors become difficult to maintain or overly verbose.
That said, XPath should be used thoughtfully. While powerful, it can become harder to read and maintain if overused. In most cases, CSS selectors remain the preferred approach in Cypress, with XPath serving as a complementary option for specific scenarios.
Cypress does not support XPath out of the box, so you need to install a plugin to enable it. Once configured, you can use the cy.xpath() command alongside standard Cypress commands.
1. Install the Cypress XPath plugin: Add the cypress-xpath package as a development dependency.
npm install --save-dev cypress-xpath
2. Import the plugin in the Cypress support file: Register the XPath command so it’s available in all your tests.
// cypress/support/e2e.js
require('cypress-xpath')
3. Verify the installation: After setup, you can use the cy.xpath() command in your test files.
cy.xpath("//button[text()='Submit']").click()
If Cypress runs without errors and recognizes the cy.xpath() command, the configuration is successful. You can now use XPath expressions in combination with Cypress’s built-in commands, retries, and assertions.
Once the cypress-xpath plugin is installed, you can use the cy.xpath() command to locate elements using XPath expressions. The syntax is straightforward and works similarly to cy.get(), except it accepts XPath instead of CSS selectors.
1. Basic usage
cy.xpath('xpath-expression')
2. Selecting an element by tag name
cy.xpath('//input')
3. Selecting by attribute
cy.xpath("//input[@type='email']")
4. Using relative XPath (recommended)
cy.xpath("//div[@class='form-container']//button")
When using XPath in Cypress, certain expressions appear frequently because they help handle dynamic elements, relationships, and text-based selection. Below are the most commonly used XPath patterns in test automation.
1. Selecting by attribute
Use @attribute to target elements with specific attribute values.
cy.xpath("//input[@name='email']").type('user@example.com')
2. Selecting by text content
The text() function allows you to match elements by their exact visible text.
cy.xpath("//button[text()='Submit']").click()
3. Using contains() for partial matches
Helpful when attributes or text are dynamic.
cy.xpath("//div[contains(@class, 'alert')]")
cy.xpath("//button[contains(text(), 'Sign')]")
4. Using logical operators
Combine multiple conditions using and or or.
cy.xpath("//input[@type='text' and @required]")
cy.xpath("//button[@type='submit' or @type='button']")
5. Navigating parent elements
Select a parent node using .. or the parent:: axis.
cy.xpath("//label[text()='Email']/parent::div")
6. Selecting child elements
Use / for direct children or // for descendants.
cy.xpath("//form//input")
7. Selecting following or preceding siblings
Useful for elements that don’t have unique attributes.
cy.xpath("//label[text()='Password']/following-sibling::input")
8. Index-based selection
Target a specific element using positional indexing (XPath indexes start at 1).
cy.xpath("(//button[@type='button'])[2]").click()
These expressions make XPath powerful for handling complex relationships and dynamic UI elements, especially when CSS selectors become limiting.
Both XPath and CSS selectors can locate elements in Cypress, but they differ in readability, maintainability, and the kinds of queries they handle best. Cypress is designed around CSS selectors, so XPath is typically a fallback option for specific situations.
1. Native support
2. Readability and team adoption
3. Strengths
4. Maintainability
5. Performance
// CSS selector (preferred when possible)
cy.get('[data-testid="submit"]').click()
// XPath selector (useful for text or relationships)
cy.xpath("//button[text()='Submit']").click()
Use CSS selectors by default, especially stable data-* attributes. Reach for XPath only when it clearly simplifies the selector, such as selecting by visible text or navigating tricky DOM relationships.
Modern web applications often generate dynamic IDs, classes, or nested structures that make element selection challenging. XPath provides flexible functions and relationship-based navigation that can help handle these dynamic scenarios more effectively.
1. Use contains() for dynamic attributes: When attributes change partially (e.g., auto-generated IDs), match only the stable portion.
cy.xpath("//div[contains(@id, 'user-card-')]")
2. Match partial text content: If button labels or messages include dynamic values, use contains(text(), ...).
cy.xpath("//button[contains(text(), 'Order')]")
3. Avoid absolute XPath paths: Absolute paths break easily when the DOM structure changes. Always prefer relative expressions.
// Fragile - absolute XPath
cy.xpath("/html/body/div[3]/div/button")
// Flexible - relative XPath
cy.xpath("//div[@class='modal']//button")
4. Leverage parent-child relationships instead of dynamic classes: If classes are unstable, target the element based on its relationship to a stable label or heading.
cy.xpath("//label[text()='Email']/following-sibling::input")
5. Combine conditions for precision: Narrow down matches using multiple conditions to avoid false positives.
cy.xpath("//input[contains(@class, 'form') and @type='text']")
When working with dynamic elements, the key is to rely on stable attributes, partial matching, and structural relationships rather than brittle, deeply nested paths. Used thoughtfully, XPath can make dynamic element handling more resilient within Cypress tests.
Read More: Software Regression Testing: Complete Guide
While XPath can be powerful, improper usage can make Cypress tests fragile and difficult to maintain. Below are common mistakes teams should avoid when using XPath in test automation.
To use XPath effectively in Cypress, treat it as a specialized tool for specific scenarios, not as a default element selection strategy.
When using XPath in Cypress, the goal should be to keep selectors clear, stable, and maintainable. Since XPath is not natively supported and requires a plugin, it should be applied thoughtfully rather than used as a default strategy.
By following these best practices, teams can use XPath in Cypress in a way that enhances flexibility without compromising test stability or maintainability.
Read More: Mastering File Upload Automation in Selenium
XPath can be a useful addition to your Cypress toolkit, especially when dealing with complex DOM structures, dynamic elements, or text-based selection scenarios where CSS selectors become limiting.
By enabling XPath through a plugin, teams gain more flexibility in how they locate and interact with elements during test execution.
However, XPath should be used thoughtfully. Since Cypress is designed around CSS selectors, those should remain the default choice for stability and simplicity.
XPath works best as a complementary strategy, applied only when it clearly improves selector clarity or solves a specific challenge.
Ultimately, writing maintainable Cypress tests is less about the selector type and more about choosing stable, readable, and resilient approaches. When used strategically, XPath can help strengthen your test automation without introducing unnecessary complexity.
Updated from Google Doc:
XPath (XML Path Language) is a query language used to navigate and select elements from an XML or HTML document. In the context of Cypress, XPath allows testers to locate elements using structured path expressions instead of traditional CSS selectors.
By default, Cypress does not support XPath. It is designed to work primarily with CSS-based selectors through commands like cy.get(). However, XPath support can be added using a plugin (such as cypress-xpath), which introduces the cy.xpath() command for locating elements.
Once enabled, XPath allows you to:
For example:
cy.xpath("//button[text()='Submit']").click()
Here, the XPath expression selects a button element based on its visible text.
In short, XPath in Cypress is an optional selector strategy that expands how you can locate elements, particularly in complex DOM structures, while still leveraging Cypress’s built-in test execution and retry capabilities.
While Cypress primarily encourages CSS selectors, there are situations where XPath offers more flexibility, especially when dealing with complex or dynamic DOM structures. XPath can be a practical alternative when CSS selectors become difficult to maintain or overly verbose.
That said, XPath should be used thoughtfully. While powerful, it can become harder to read and maintain if overused. In most cases, CSS selectors remain the preferred approach in Cypress, with XPath serving as a complementary option for specific scenarios.
Cypress does not support XPath out of the box, so you need to install a plugin to enable it. Once configured, you can use the cy.xpath() command alongside standard Cypress commands.
1. Install the Cypress XPath plugin: Add the cypress-xpath package as a development dependency.
npm install --save-dev cypress-xpath
2. Import the plugin in the Cypress support file: Register the XPath command so it’s available in all your tests.
// cypress/support/e2e.js
require('cypress-xpath')
3. Verify the installation: After setup, you can use the cy.xpath() command in your test files.
cy.xpath("//button[text()='Submit']").click()
If Cypress runs without errors and recognizes the cy.xpath() command, the configuration is successful. You can now use XPath expressions in combination with Cypress’s built-in commands, retries, and assertions.
Once the cypress-xpath plugin is installed, you can use the cy.xpath() command to locate elements using XPath expressions. The syntax is straightforward and works similarly to cy.get(), except it accepts XPath instead of CSS selectors.
1. Basic usage
cy.xpath('xpath-expression')
2. Selecting an element by tag name
cy.xpath('//input')
3. Selecting by attribute
cy.xpath("//input[@type='email']")
4. Using relative XPath (recommended)
cy.xpath("//div[@class='form-container']//button")
When using XPath in Cypress, certain expressions appear frequently because they help handle dynamic elements, relationships, and text-based selection. Below are the most commonly used XPath patterns in test automation.
1. Selecting by attribute
Use @attribute to target elements with specific attribute values.
cy.xpath("//input[@name='email']").type('user@example.com')
2. Selecting by text content
The text() function allows you to match elements by their exact visible text.
cy.xpath("//button[text()='Submit']").click()
3. Using contains() for partial matches
Helpful when attributes or text are dynamic.
cy.xpath("//div[contains(@class, 'alert')]")
cy.xpath("//button[contains(text(), 'Sign')]")
4. Using logical operators
Combine multiple conditions using and or or.
cy.xpath("//input[@type='text' and @required]")
cy.xpath("//button[@type='submit' or @type='button']")
5. Navigating parent elements
Select a parent node using .. or the parent:: axis.
cy.xpath("//label[text()='Email']/parent::div")
6. Selecting child elements
Use / for direct children or // for descendants.
cy.xpath("//form//input")
7. Selecting following or preceding siblings
Useful for elements that don’t have unique attributes.
cy.xpath("//label[text()='Password']/following-sibling::input")
8. Index-based selection
Target a specific element using positional indexing (XPath indexes start at 1).
cy.xpath("(//button[@type='button'])[2]").click()
These expressions make XPath powerful for handling complex relationships and dynamic UI elements, especially when CSS selectors become limiting.
Both XPath and CSS selectors can locate elements in Cypress, but they differ in readability, maintainability, and the kinds of queries they handle best. Cypress is designed around CSS selectors, so XPath is typically a fallback option for specific situations.
1. Native support
2. Readability and team adoption
3. Strengths
4. Maintainability
5. Performance
// CSS selector (preferred when possible)
cy.get('[data-testid="submit"]').click()
// XPath selector (useful for text or relationships)
cy.xpath("//button[text()='Submit']").click()
Use CSS selectors by default, especially stable data-* attributes. Reach for XPath only when it clearly simplifies the selector, such as selecting by visible text or navigating tricky DOM relationships.
Modern web applications often generate dynamic IDs, classes, or nested structures that make element selection challenging. XPath provides flexible functions and relationship-based navigation that can help handle these dynamic scenarios more effectively.
1. Use contains() for dynamic attributes: When attributes change partially (e.g., auto-generated IDs), match only the stable portion.
cy.xpath("//div[contains(@id, 'user-card-')]")
2. Match partial text content: If button labels or messages include dynamic values, use contains(text(), ...).
cy.xpath("//button[contains(text(), 'Order')]")
3. Avoid absolute XPath paths: Absolute paths break easily when the DOM structure changes. Always prefer relative expressions.
// Fragile - absolute XPath
cy.xpath("/html/body/div[3]/div/button")
// Flexible - relative XPath
cy.xpath("//div[@class='modal']//button")
4. Leverage parent-child relationships instead of dynamic classes: If classes are unstable, target the element based on its relationship to a stable label or heading.
cy.xpath("//label[text()='Email']/following-sibling::input")
5. Combine conditions for precision: Narrow down matches using multiple conditions to avoid false positives.
cy.xpath("//input[contains(@class, 'form') and @type='text']")
When working with dynamic elements, the key is to rely on stable attributes, partial matching, and structural relationships rather than brittle, deeply nested paths. Used thoughtfully, XPath can make dynamic element handling more resilient within Cypress tests.
Read More: Software Regression Testing: Complete Guide
While XPath can be powerful, improper usage can make Cypress tests fragile and difficult to maintain. Below are common mistakes teams should avoid when using XPath in test automation.
To use XPath effectively in Cypress, treat it as a specialized tool for specific scenarios, not as a default element selection strategy.
When using XPath in Cypress, the goal should be to keep selectors clear, stable, and maintainable. Since XPath is not natively supported and requires a plugin, it should be applied thoughtfully rather than used as a default strategy.
By following these best practices, teams can use XPath in Cypress in a way that enhances flexibility without compromising test stability or maintainability.
Read More: Mastering File Upload Automation in Selenium
XPath can be a useful addition to your Cypress toolkit, especially when dealing with complex DOM structures, dynamic elements, or text-based selection scenarios where CSS selectors become limiting.
By enabling XPath through a plugin, teams gain more flexibility in how they locate and interact with elements during test execution.
However, XPath should be used thoughtfully. Since Cypress is designed around CSS selectors, those should remain the default choice for stability and simplicity.
XPath works best as a complementary strategy, applied only when it clearly improves selector clarity or solves a specific challenge.
Adding some additional text for testinnggg
Ultimately, writing maintainable Cypress tests is less about the selector type and more about choosing stable, readable, and resilient approaches. When used strategically, XPath can help strengthen your test automation without introducing unnecessary complexity.
Get visual proof, steps to reproduce and technical logs with one click
Try Bird on your next bug - you’ll love it
“Game changer”
Julie, Head of QA
Try Bird later, from your desktop