CSS selectors are a key way to locate elements on a web page when automating tests with Selenium. They provide a simple and efficient method to target elements by ID, class, tag, or other attributes. Using CSS selectors correctly can make test scripts faster and easier to maintain.
With CSS selectors, testers can handle both basic and complex scenarios, such as selecting child elements, siblings, or elements with specific attribute values.
This article explores CSS selectors in Selenium with examples and best practices.
CSS selectors are patterns used to select HTML elements based on their attributes, hierarchy, or relationships in the DOM. In Selenium, they serve as a way to precisely identify elements for actions like clicking, typing, or verifying content. Compared to XPath, CSS selectors are generally faster and easier to read, especially for simple element selections.
CSS selectors can target elements using IDs, classes, tags, attributes, or combinations of these. They also support relationships such as parent–child, siblings, and pseudo-classes, allowing testers to handle complex web structures. Correct usage ensures stable and maintainable test scripts.
CSS selectors in Selenium provide a flexible way to locate elements for automation scripts. By using different patterns, testers can target elements precisely, reduce flakiness in tests, and make scripts easier to maintain. The following core patterns cover the most common selection methods used in real-world Selenium automation.
The ID of an element is unique within a page, making it the most precise selector. Using IDs ensures the selection is fast and reliable.
Syntax: #elementID
Example: #username
This selects the element <input id="username">. In Selenium:
driver.findElement(By.cssSelector("#username")).sendKeys("testuser");
Classes can be shared across multiple elements, so using class selectors is useful when you want to target a group of elements or a specific one with a unique combination.
Syntax: .className
Example: .login-button
This selects all elements with class="login-button". In Selenium:
driver.findElement(By.cssSelector(".login-button")).click();
Tag selectors are useful when elements have no unique ID or class but are identified by their HTML tag. This is often combined with other selectors for precision.
Syntax: tagname
Example: input
This selects all <input> elements on the page. In Selenium:
driver.findElements(By.cssSelector("input"));
Attribute selectors allow targeting elements based on any attribute, not just ID or class. This is useful for forms, buttons, and links.
Syntax: [attribute='value']
Example: [type='submit']
This selects <input type="submit">. In Selenium:
driver.findElement(By.cssSelector("[type='submit']")).click();
Sometimes a single attribute is not enough to uniquely identify an element. Combining attributes increases specificity.
Syntax: [attr1='value1'][attr2='value2']
Example: [type='text'][name='email']
This selects <input type="text" name="email">. In Selenium:
driver.findElement(By.cssSelector("[type='text'][name='email']")).sendKeys("user@example.com");
Advanced CSS selectors help handle elements that are difficult to locate using simple patterns. Using these strategies in Selenium improves test reliability, especially for dynamic or complex web pages.
This approach targets elements based on partial attribute values, useful when IDs or classes change dynamically. For example, [id^='user'] selects any element whose ID starts with "user", such as <input id="user123">.
Similarly, [class*='btn'] matches elements containing "btn" in their class name, like <button class="submit-btn">. Substring matching ensures tests continue to work even if small changes occur in attribute values.
Selecting elements based on hierarchy allows precise targeting. The child selector (>) selects elements directly under a parent, e.g., div > input finds input fields immediately inside a <div>.
Descendant selectors (space) capture elements at any depth, e.g., form input selects all input fields within a form. These relationships help handle nested structures without relying on fragile attributes.
When elements appear sequentially, sibling selectors locate elements relative to others. The adjacent sibling selector (+) targets the next element, e.g., label + input finds an input immediately after a label. The general sibling selector (~) selects all following siblings, useful for grouped form controls or list items.
Grouping combines multiple selectors to reduce repetition and improve readability. For example, input, select, and textarea selects all standard form fields in a single expression. Grouping simplifies scripts and makes them easier to maintain when multiple elements need the same action.
Pseudo-classes allow selection based on position or state. Examples include :first-child, :last-child, and :nth-of-type(n). For instance, ul li:nth-of-type(2) selects the second list item in every unordered list. Pseudo-classes are valuable when elements lack unique IDs or consistent attributes, letting testers rely on structure instead.
Using CSS selectors in Selenium test scripts helps locate elements quickly and perform actions efficiently. Here are practical examples demonstrating common scenarios:
1. Selecting Elements by ID
When an element has a unique ID, it is the most reliable selector. For example, to enter a username in a login form:
driver.findElement(By.cssSelector("#username")).sendKeys("testuser");
This selects <input id="username"> directly and ensures the action targets the correct field.
2. Selecting Elements by Class
Classes are useful when multiple elements share the same styling or behavior. For instance, clicking a submit button with class login-button:
driver.findElement(By.cssSelector(".login-button")).click();
If multiple buttons exist, combining the class with another attribute improves specificity.
3. Selecting Elements by Attribute
Attribute selectors handle elements without IDs or unique classes. For example, selecting a submit input field by its type attribute:
driver.findElement(By.cssSelector("input[type='submit']")).click();
This works reliably even if the element has dynamic classes.
4. Combining Multiple Attributes
Combining attributes increases precision when a single attribute is insufficient. For example:
driver.findElement(By.cssSelector("input[type='text'][name='email']")).sendKeys("user@example.com");
This ensures only the input field intended for the email is selected, reducing the risk of interacting with the wrong element.
5. Using Advanced Selectors
Advanced selectors like child, descendant, and pseudo-classes handle complex page structures. For example, selecting the second item in a list inside a form:
driver.findElement(By.cssSelector("form ul li:nth-of-type(2)")).click();
This approach is particularly useful for dynamic lists or repeated elements without unique identifiers.
Following best practices ensures that CSS selectors remain reliable, maintainable, and efficient in Selenium test scripts.
Effective use of CSS selectors in Selenium is key to creating robust and maintainable automation scripts. By leveraging IDs, classes, attributes, and advanced strategies like substring matching, pseudo-classes, and parent–child relationships, testers can accurately target elements even in complex or dynamic web pages.
For teams looking to scale testing across multiple browsers and devices, BrowserStack Automate provides a cloud-based platform to execute Selenium scripts reliably. It supports real-device and browser testing, enabling verification of CSS selectors in diverse environments without the overhead of maintaining local infrastructure.
Run Selenium Tests on Cloud
Get visual proof, steps to reproduce and technical logs with one click
Continue reading
Try Bird on your next bug - you’ll love it
“Game changer”
Julie, Head of QA
Try Bird later, from your desktop