Best default
Prefer IDs, stable attributes, and readable CSS before moving to complex XPath.
A focused locator reference for stable Selenium tests: CSS, XPath, lists, dynamic IDs, and relative locators.
Prefer IDs, stable attributes, and readable CSS before moving to complex XPath.
Form fields, tables, lists, dynamic pages, legacy apps, and troubleshooting flaky element lookup.
Overly brittle locators tied to styling or unstable DOM structure.
Use this with the waits sheet so lookup and synchronization stay aligned.
Start with the simplest stable locator available.
driver.findElement(By.id("username"));
driver.findElement(By.name("email"));
driver.findElement(By.className("btn-primary"));
driver.findElement(By.tagName("input"));
driver.findElement(By.linkText("Login"));
CSS is compact and fast for many common element lookups.
By.cssSelector("#username");
By.cssSelector(".btn.primary");
By.cssSelector("input[type='email']");
By.cssSelector("form button[type='submit']");
Use attribute selectors and combinators for readable structure-based targeting.
By.cssSelector("div.card > h2");
By.cssSelector("ul li:first-child");
By.cssSelector("input[placeholder*='Search']");
By.cssSelector("[data-testid='save-button']");
XPath is powerful when CSS is not enough, especially in legacy DOMs.
By.xpath("//input");
By.xpath("//button[@type='submit']");
By.xpath("//a[text()='Dashboard']");
By.xpath("//div[contains(@class,'card')]");
Relative XPath is usually safer than absolute full-page paths.
//div[@id='login-form']//input[@name='password']
Axes help when the relationship between elements matters more than raw attributes.
//label[text()='Email']/following-sibling::input //td[text()='Total']/preceding-sibling::td //button[@id='save']/ancestor::form
Functions make locators more flexible when exact text or attributes are not stable.
//button[contains(text(),'Save')] //input[starts-with(@id,'user_')] //a[contains(@href,'checkout')] //span[normalize-space()='Submit']
Use lists when validating tables, collections, or repeated UI blocks.
Listrows = driver.findElements(By.cssSelector("table tbody tr")); for (WebElement row : rows) { System.out.println(row.getText()); }
Use smart fallbacks for dynamic IDs and Selenium 4 relative locators where they improve readability.
By.xpath("//input[contains(@id,'email')]");
WebElement password = driver.findElement(By.id("password"));
driver.findElement(with(By.tagName("button")).below(password));