Junior QASeleniumFree question
CSS selector vs XPath: which is better and why?
60-second answer
Both work in all modern browsers. CSS selectors are usually shorter, more readable and slightly faster, and they're what front-end developers use, so they're easy to share. XPath is more powerful: it can match by visible text and navigate upwards to parents and ancestors, which CSS can't do. My rule is to use id or a data-testid first, then CSS for most locators, and XPath only when I need text matching or to move up the DOM. Speed differences are negligible in practice; stability matters more.
Explanation
| Need | CSS | XPath |
|---|---|---|
| By id | #email | //*[@id='email'] |
| By class | .btn.primary | //*[contains(@class,'primary')] |
| Attribute | [data-testid='save'] | //*[@data-testid='save'] |
| Starts / contains | [id^='btn'], [id*='btn'] | starts-with(), contains() |
| Child | form > input | //form/input |
| Nth | li:nth-child(3) | (//li)[3] |
| Text | Not supported | //button[text()='Save'] |
| Parent / ancestor | Not supported (:has() in modern browsers only) | parent::, ancestor:: |
Example
"Click the Save button" → button[data-testid='save'] (CSS). "Click Edit next to the user named Priya" → XPath with text and ancestor.
Sample code
By cssSave = By.cssSelector("form#profile button[type='submit']");
By xpathSave = By.xpath("//form[@id='profile']//button[@type='submit']");
// XPath only: by visible text, then up to the row
By editPriya = By.xpath("//td[text()='Priya']/parent::tr//a[text()='Edit']");