
Selenium findElement and findElements Examples
Selenium WebDriver’s findElement and findElements methods are fundamental building blocks for web automation testing, allowing you to locate and interact with HTML elements on web pages. While both methods use the same locator strategies, they behave differently when elements are found or missing, which can make or break your test automation scripts. In this post, you’ll learn the key differences between these methods, see practical examples of each locator strategy, understand when to use which approach, and discover common pitfalls that can save you hours of debugging.
How findElement and findElements Work
The core difference between findElement and findElements lies in their return behavior and exception handling. The findElement method returns a single WebElement object and throws a NoSuchElementException if no element is found. Meanwhile, findElements returns a List of WebElement objects and returns an empty list when no elements match the locator.
Both methods accept By objects as parameters, which define the locator strategy. Selenium supports eight primary locator strategies: ID, Name, Class Name, Tag Name, Link Text, Partial Link Text, CSS Selector, and XPath. Each strategy has its strengths and performance characteristics.
Method | Return Type | When No Element Found | When Multiple Elements Found |
---|---|---|---|
findElement | WebElement | Throws NoSuchElementException | Returns first matching element |
findElements | List<WebElement> | Returns empty list | Returns all matching elements |
Step-by-Step Implementation Guide
Let’s start with basic setup and then explore each locator strategy with practical examples. First, ensure you have Selenium WebDriver dependencies in your project:
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.15.0</version>
</dependency>
Here’s the basic WebDriver setup:
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;
import java.util.List;
public class SeleniumLocatorExamples {
private WebDriver driver;
public void setUp() {
driver = new ChromeDriver();
driver.get("https://example.com");
}
}
ID Locator Strategy
ID locators are the fastest and most reliable when available, since IDs should be unique on a page:
// findElement with ID
WebElement loginButton = driver.findElement(By.id("login-btn"));
loginButton.click();
// findElements with ID (typically returns 0 or 1 element)
List<WebElement> loginElements = driver.findElements(By.id("login-btn"));
if (!loginElements.isEmpty()) {
loginElements.get(0).click();
}
Name Locator Strategy
Name locators work well for form elements:
// Single element by name
WebElement usernameField = driver.findElement(By.name("username"));
usernameField.sendKeys("testuser");
// Multiple elements by name (common with radio buttons)
List<WebElement> radioButtons = driver.findElements(By.name("gender"));
for (WebElement radio : radioButtons) {
if (radio.getAttribute("value").equals("male")) {
radio.click();
break;
}
}
CSS Selector Strategy
CSS selectors offer powerful and flexible element targeting:
// Class selector
WebElement errorMessage = driver.findElement(By.cssSelector(".error-message"));
// Attribute selector
WebElement emailInput = driver.findElement(By.cssSelector("input[type='email']"));
// Complex CSS selector
List<WebElement> navLinks = driver.findElements(By.cssSelector("nav ul li a"));
// Pseudo-selectors
WebElement firstListItem = driver.findElement(By.cssSelector("ul li:first-child"));
WebElement lastRow = driver.findElement(By.cssSelector("table tr:last-child"));
XPath Strategy
XPath provides the most powerful but potentially slowest locator option:
// Absolute XPath (fragile, not recommended)
WebElement element = driver.findElement(By.xpath("/html/body/div[1]/form/input[2]"));
// Relative XPath with text content
WebElement submitBtn = driver.findElement(By.xpath("//button[text()='Submit']"));
// XPath with contains function
WebElement partialText = driver.findElement(By.xpath("//span[contains(text(), 'Welcome')]"));
// XPath with multiple conditions
List<WebElement> activeUsers = driver.findElements(
By.xpath("//tr[@class='user-row' and contains(@data-status, 'active')]")
);
// XPath axes
WebElement nextSibling = driver.findElement(
By.xpath("//label[text()='Username']/following-sibling::input")
);
Real-World Examples and Use Cases
Here are practical scenarios where you’d choose findElement vs findElements:
Form Validation Scenario
public boolean validateLoginForm() {
try {
// Use findElement when you expect exactly one element
WebElement usernameField = driver.findElement(By.name("username"));
WebElement passwordField = driver.findElement(By.name("password"));
// Use findElements to check if error messages exist
List<WebElement> errorMessages = driver.findElements(By.className("validation-error"));
return errorMessages.isEmpty(); // No errors = valid form
} catch (NoSuchElementException e) {
return false; // Required fields missing
}
}
Dynamic Content Handling
public void handleDynamicTable() {
// Get all table rows
List<WebElement> tableRows = driver.findElements(By.cssSelector("table tbody tr"));
System.out.println("Found " + tableRows.size() + " rows");
for (int i = 0; i < tableRows.size(); i++) {
WebElement row = tableRows.get(i);
// Find cells within this specific row
List<WebElement> cells = row.findElements(By.tagName("td"));
if (cells.size() >= 3) {
String name = cells.get(0).getText();
String email = cells.get(1).getText();
String status = cells.get(2).getText();
System.out.println("Row " + i + ": " + name + " | " + email + " | " + status);
}
}
}
Wait Strategy Implementation
import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.support.ui.ExpectedConditions;
import java.time.Duration;
public WebElement waitForElement(By locator, int timeoutSeconds) {
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(timeoutSeconds));
return wait.until(ExpectedConditions.presenceOfElementLocated(locator));
}
public List<WebElement> waitForElements(By locator, int timeoutSeconds) {
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(timeoutSeconds));
wait.until(ExpectedConditions.presenceOfElementLocated(locator));
return driver.findElements(locator);
}
Performance Comparison and Best Practices
Different locator strategies have varying performance characteristics. Here’s a performance ranking from fastest to slowest:
Locator Strategy | Performance | Reliability | Best Use Case |
---|---|---|---|
ID | Fastest | High | Unique elements with stable IDs |
Name | Fast | Medium | Form elements |
CSS Selector | Fast | High | Complex selections, modern web apps |
Class Name | Fast | Medium | Elements with unique classes |
Tag Name | Medium | Low | When combined with other strategies |
Link Text | Medium | Medium | Static link text |
Partial Link Text | Slow | Medium | Dynamic or long link text |
XPath | Slowest | High | Complex relationships, text content |
Best Practices
- Always prefer findElements when checking element existence to avoid exceptions
- Use explicit waits instead of Thread.sleep() for better reliability
- Combine locator strategies for more robust element identification
- Avoid absolute XPath expressions as they’re brittle to DOM changes
- Cache frequently used elements but be aware of stale element references
- Use Page Object Model pattern to centralize element definitions
// Good: Check existence before interaction
List<WebElement> notifications = driver.findElements(By.className("notification"));
if (!notifications.isEmpty()) {
notifications.get(0).click();
}
// Better: Use explicit wait
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
WebElement notification = wait.until(
ExpectedConditions.elementToBeClickable(By.className("notification"))
);
notification.click();
Common Pitfalls and Troubleshooting
Stale Element Reference Exception
This occurs when you hold references to elements that are no longer attached to the DOM:
// Problematic approach
List<WebElement> items = driver.findElements(By.className("item"));
// Page refresh or DOM manipulation happens
items.get(0).click(); // Throws StaleElementReferenceException
// Solution: Re-find elements after DOM changes
public void clickFirstItem() {
List<WebElement> items = driver.findElements(By.className("item"));
if (!items.isEmpty()) {
items.get(0).click();
}
}
Timing Issues
Elements might not be immediately available due to JavaScript loading:
// Wrong: Immediate search might fail
WebElement dynamicContent = driver.findElement(By.id("dynamic-content"));
// Right: Wait for element to appear
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
WebElement dynamicContent = wait.until(
ExpectedConditions.presenceOfElementLocated(By.id("dynamic-content"))
);
Shadow DOM Elements
Regular locators don’t work with Shadow DOM. You need to use JavaScript execution:
import org.openqa.selenium.JavascriptExecutor;
public WebElement findElementInShadowDOM(String shadowHost, String selector) {
JavascriptExecutor js = (JavascriptExecutor) driver;
return (WebElement) js.executeScript(
"return document.querySelector(arguments[0]).shadowRoot.querySelector(arguments[1])",
shadowHost, selector
);
}
iframe Context Issues
Elements inside iframes require context switching:
// Switch to iframe first
driver.switchTo().frame("iframe-name");
WebElement elementInFrame = driver.findElement(By.id("element-in-iframe"));
// Switch back to main content
driver.switchTo().defaultContent();
Understanding these nuances of findElement and findElements will significantly improve your Selenium automation scripts’ reliability and maintainability. The key is choosing the right method based on your specific use case and handling edge cases gracefully. For more detailed information, check the official Selenium documentation and the W3C WebDriver specification.

This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.
This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.