Skip to main content
SeleniumDecoded

CSS Selectors

Master CSS selectors for finding elements in Selenium. Learn syntax, best practices, and common patterns.

Selenium 3 & 4 Stable

CSS selectors are the recommended way to locate elements in Selenium. They’re faster than XPath, more readable, and widely understood by web developers.

Basic Selectors

By ID

Select by ID
Selenium 3 & 4 Stable
// Using CSS selector
WebElement element = driver.findElement(By.cssSelector("#username"));
// Equivalent using By.id
WebElement element = driver.findElement(By.id("username"));
# Using CSS selector
element = driver.find_element(By.CSS_SELECTOR, "#username")
# Equivalent using By.ID
element = driver.find_element(By.ID, "username")
// Using CSS selector
const element = await driver.findElement(By.css('#username'));
// Equivalent using By.id
const element = await driver.findElement(By.id('username'));
// Using CSS selector
IWebElement element = driver.FindElement(By.CssSelector("#username"));
// Equivalent using By.Id
IWebElement element = driver.FindElement(By.Id("username"));

By Class

Select by Class
Selenium 3 & 4 Stable
// Single class
WebElement element = driver.findElement(By.cssSelector(".btn-primary"));
// Multiple classes (element has both classes)
WebElement element = driver.findElement(By.cssSelector(".btn.btn-primary"));
# Single class
element = driver.find_element(By.CSS_SELECTOR, ".btn-primary")
# Multiple classes (element has both classes)
element = driver.find_element(By.CSS_SELECTOR, ".btn.btn-primary")
// Single class
const element = await driver.findElement(By.css('.btn-primary'));
// Multiple classes (element has both classes)
const element = await driver.findElement(By.css('.btn.btn-primary'));
// Single class
IWebElement element = driver.FindElement(By.CssSelector(".btn-primary"));
// Multiple classes (element has both classes)
IWebElement element = driver.FindElement(By.CssSelector(".btn.btn-primary"));

By Tag Name

Select by Tag
Selenium 3 & 4 Stable
// All buttons
List<WebElement> buttons = driver.findElements(By.cssSelector("button"));
// All inputs of type text
List<WebElement> textInputs = driver.findElements(By.cssSelector("input[type='text']"));
# All buttons
buttons = driver.find_elements(By.CSS_SELECTOR, "button")
# All inputs of type text
text_inputs = driver.find_elements(By.CSS_SELECTOR, "input[type='text']")
// All buttons
const buttons = await driver.findElements(By.css('button'));
// All inputs of type text
const textInputs = await driver.findElements(By.css("input[type='text']"));
// All buttons
IList<IWebElement> buttons = driver.FindElements(By.CssSelector("button"));
// All inputs of type text
IList<IWebElement> textInputs = driver.FindElements(By.CssSelector("input[type='text']"));

Attribute Selectors

SelectorDescription
[attr]Has attribute
[attr='value']Exact match
[attr^='value']Starts with
[attr$='value']Ends with
[attr*='value']Contains
Attribute Selectors
Selenium 3 & 4 Stable
// Has attribute
driver.findElement(By.cssSelector("[data-testid]"));
// Exact match
driver.findElement(By.cssSelector("[data-testid='submit-btn']"));
// Starts with
driver.findElement(By.cssSelector("[id^='user_']"));
// Ends with
driver.findElement(By.cssSelector("[id$='_input']"));
// Contains
driver.findElement(By.cssSelector("[class*='primary']"));
# Has attribute
driver.find_element(By.CSS_SELECTOR, "[data-testid]")
# Exact match
driver.find_element(By.CSS_SELECTOR, "[data-testid='submit-btn']")
# Starts with
driver.find_element(By.CSS_SELECTOR, "[id^='user_']")
# Ends with
driver.find_element(By.CSS_SELECTOR, "[id$='_input']")
# Contains
driver.find_element(By.CSS_SELECTOR, "[class*='primary']")
// Has attribute
await driver.findElement(By.css('[data-testid]'));
// Exact match
await driver.findElement(By.css("[data-testid='submit-btn']"));
// Starts with
await driver.findElement(By.css("[id^='user_']"));
// Ends with
await driver.findElement(By.css("[id$='_input']"));
// Contains
await driver.findElement(By.css("[class*='primary']"));
// Has attribute
driver.FindElement(By.CssSelector("[data-testid]"));
// Exact match
driver.FindElement(By.CssSelector("[data-testid='submit-btn']"));
// Starts with
driver.FindElement(By.CssSelector("[id^='user_']"));
// Ends with
driver.FindElement(By.CssSelector("[id$='_input']"));
// Contains
driver.FindElement(By.CssSelector("[class*='primary']"));

Combinators

Descendant (space)

Selects all descendants:

div.container p /* All <p> inside div.container */

Child (>)

Selects only direct children:

ul > li /* Direct <li> children of <ul> */

Adjacent Sibling (+)

Selects the immediate next sibling:

h2 + p /* <p> immediately after <h2> */

General Sibling (~)

Selects all following siblings:

h2 ~ p /* All <p> after <h2> at same level */
Combinator Examples
Selenium 3 & 4 Stable
// Descendant - any depth
driver.findElement(By.cssSelector("form input"));
// Direct child only
driver.findElement(By.cssSelector("ul > li"));
// Adjacent sibling
driver.findElement(By.cssSelector("label + input"));
// General sibling
driver.findElements(By.cssSelector("h2 ~ p"));
# Descendant - any depth
driver.find_element(By.CSS_SELECTOR, "form input")
# Direct child only
driver.find_element(By.CSS_SELECTOR, "ul > li")
# Adjacent sibling
driver.find_element(By.CSS_SELECTOR, "label + input")
# General sibling
driver.find_elements(By.CSS_SELECTOR, "h2 ~ p")
// Descendant - any depth
await driver.findElement(By.css('form input'));
// Direct child only
await driver.findElement(By.css('ul > li'));
// Adjacent sibling
await driver.findElement(By.css('label + input'));
// General sibling
await driver.findElements(By.css('h2 ~ p'));
// Descendant - any depth
driver.FindElement(By.CssSelector("form input"));
// Direct child only
driver.FindElement(By.CssSelector("ul > li"));
// Adjacent sibling
driver.FindElement(By.CssSelector("label + input"));
// General sibling
driver.FindElements(By.CssSelector("h2 ~ p"));

Pseudo-Selectors

nth-child

Position-Based Selection
Selenium 3 & 4 Medium
// First item
driver.findElement(By.cssSelector("ul li:first-child"));
// Last item
driver.findElement(By.cssSelector("ul li:last-child"));
// Second item (1-indexed)
driver.findElement(By.cssSelector("ul li:nth-child(2)"));
// Every odd item
driver.findElements(By.cssSelector("tr:nth-child(odd)"));
// Every 3rd item
driver.findElements(By.cssSelector("li:nth-child(3n)"));
# First item
driver.find_element(By.CSS_SELECTOR, "ul li:first-child")
# Last item
driver.find_element(By.CSS_SELECTOR, "ul li:last-child")
# Second item (1-indexed)
driver.find_element(By.CSS_SELECTOR, "ul li:nth-child(2)")
# Every odd item
driver.find_elements(By.CSS_SELECTOR, "tr:nth-child(odd)")
# Every 3rd item
driver.find_elements(By.CSS_SELECTOR, "li:nth-child(3n)")
// First item
await driver.findElement(By.css('ul li:first-child'));
// Last item
await driver.findElement(By.css('ul li:last-child'));
// Second item (1-indexed)
await driver.findElement(By.css('ul li:nth-child(2)'));
// Every odd item
await driver.findElements(By.css('tr:nth-child(odd)'));
// Every 3rd item
await driver.findElements(By.css('li:nth-child(3n)'));
// First item
driver.FindElement(By.CssSelector("ul li:first-child"));
// Last item
driver.FindElement(By.CssSelector("ul li:last-child"));
// Second item (1-indexed)
driver.FindElement(By.CssSelector("ul li:nth-child(2)"));
// Every odd item
driver.FindElements(By.CssSelector("tr:nth-child(odd)"));
// Every 3rd item
driver.FindElements(By.CssSelector("li:nth-child(3n)"));

CSS vs XPath

FeatureCSSXPath
SpeedFasterSlower
ReadabilityMore intuitiveCan be complex
Text contentCannot select by textCan select by text
AxesLimited (descendants, siblings)Full (parent, ancestor, etc.)
Browser supportExcellentExcellent

Recommendation: Use CSS selectors as your default. Switch to XPath only when you need features CSS doesn’t support (like selecting by text or navigating to parent elements).

Want to master XPath selectors? Visit XPath Decoded

Best Practices

  1. Prefer IDs over classes: #submit-btn is more stable than .btn-primary
  2. Use data attributes: [data-testid='login-form'] is designed for testing
  3. Keep selectors short: Avoid deeply nested selectors
  4. Avoid indexes when possible: :nth-child(2) breaks if order changes
  5. Test selectors in DevTools: Use $$('selector') in browser console

Next Steps