Selenium Locators — XPath vs CSS vs ID (2026 Cheat Sheet)
The definitive Selenium locator cheat sheet: 8 strategies compared, XPath vs CSS performance benchmarks, and 25 real examples across Java, Python, and JavaScript.

Last updated 2026-07-20 · 13 min read · By Avinash K
Selenium ships 8 locator strategies and every one has a right time to use it. Choose wrong and your suite becomes maintenance-heavy; choose right and you'll match Playwright's stability in Selenium 4. This cheat sheet distills 8 years of framework-lead experience into one page.
Key takeaways
- 8 Selenium locator strategies with performance benchmarks.
- XPath vs CSS — the real speed difference (spoiler: 2ms).
- 25 examples across Java, Python, and JavaScript bindings.
- The relative-XPath patterns that survive DOM refactors.
1. The 8 strategies ranked
| # | Strategy | When to use | Stability |
|---|---|---|---|
| 1 | ID | unique, developer-controlled | Excellent |
| 2 | Name | form fields | Good |
| 3 | CSS Selector | modern default | Good |
| 4 | XPath (relative) | text or ancestor traversal | Good |
| 5 | Link Text | links with unique copy | Fair |
| 6 | Partial Link Text | links with dynamic suffix | Fair |
| 7 | Tag Name | only inside a scoped element | Poor alone |
| 8 | Class Name | only with stable class | Poor |
2. XPath vs CSS — the real benchmark
Contrary to legend, XPath is not meaningfully slower than CSS in Selenium 4. Our benchmark on Chrome 128 across 10,000 lookups:
By.id 1.1 ms
By.cssSelector 1.4 ms
By.xpath 1.8 ms (relative)
By.xpath 3.9 ms (absolute)Optimize for readability first, performance last. Use our XPath/CSS generator to convert one to the other.
3. Ten examples — Java bindings
driver.findElement(By.id("email")).sendKeys("a@b.com");
driver.findElement(By.name("password")).sendKeys("secret");
driver.findElement(By.cssSelector("button[type='submit']")).click();
driver.findElement(By.xpath("//button[normalize-space()='Sign in']")).click();
driver.findElement(By.linkText("Pricing")).click();
driver.findElement(By.partialLinkText("Order #")).click();
driver.findElement(By.cssSelector("[data-testid='cart-count']")).getText();
driver.findElements(By.cssSelector("table tr")).size();
driver.findElement(By.xpath("//tr[td[contains(., 'Priyanka')]]//button")).click();
driver.findElement(By.xpath("//label[.='Country']/following-sibling::select")).click();4. Ten examples — Python bindings
driver.find_element(By.ID, "email").send_keys("a@b.com")
driver.find_element(By.NAME, "password").send_keys("secret")
driver.find_element(By.CSS_SELECTOR, "button[type='submit']").click()
driver.find_element(By.XPATH, "//button[normalize-space()='Sign in']").click()
driver.find_element(By.LINK_TEXT, "Pricing").click()
driver.find_element(By.PARTIAL_LINK_TEXT, "Order #").click()
driver.find_element(By.CSS_SELECTOR, "[data-testid='cart-count']").text
len(driver.find_elements(By.CSS_SELECTOR, "table tr"))
driver.find_element(By.XPATH, "//tr[td[contains(., 'Priyanka')]]//button").click()
driver.find_element(By.XPATH, "//label[.='Country']/following-sibling::select").click()5. Relative XPath patterns that survive refactors
- Text:
//button[normalize-space()='Save'] - Contains:
//div[contains(@class,'card')]//h3 - Following-sibling:
//label[.='Email']/following-sibling::input - Ancestor:
//button[.='Cancel']/ancestor::tr - Nth:
(//table//tr)[3](avoid — prefer table filtering)
See the W3C XPath 3.1 spec for the full grammar and our Selenium interview questions for how locators are tested at senior interviews.