> For the complete documentation index, see [llms.txt](https://docs.dogq.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.dogq.io/documentation/selectors/css-selectors-101.md).

# CSS Selectors 101

CSS barely needs an introduction. In web development it's used for selecting and styling HTML elements. In this guide we will only be discussing the usage of CSS selectors in the testing realm.

<details>

<summary>CSS Syntax Cheat Sheet</summary>

**Basic selectors**

* **element** - selects all elements with the given tag name
* **.class** - selects all elements by class name
* **#id** - selects all elements with the given id
* **\[attribute="value"]** - selects all elements with the given attribute-value pair

**Compound selectors**

* \[attribute1="valu&#x65;**"**]\[attribute2="value"]
* .class1.class2.class3
* .class#id
* element#id\[attribute=value]

**Combinators**

* **A B** - selects descendant **B** of parent **A** at any level, i.e. child, grandchild, etc.
* **A > B** - selects descendant **B** of parent **A** at child level, i.e. not further
* **A + B** - selects element **B** that immediately follows its sibling **A**
* **A \~ B** - selects element **B** that follows its sibling **A** (not necessarily immediately)

**Operators**

* \[attribut&#x65;**=**&#x76;alue] - exact matching
* \[attribut&#x65;**\*=**&#x76;alue] - partial matching (substring)
* \[attribut&#x65;**^=**&#x76;alue] - matching substring at the start of the value
* \[attribut&#x65;**$=**&#x76;alue] - matching substring at the end of the value

</details>

### CSS Selectors in testing

Every element that you interact with in an automated test (whether it’s clicking, typing, asserting, etc.) needs to be uniquely identified so that it can be located during the test run. CSS selectors allow automated testing frameworks to do just that. In addition to targeting an element, they can also be used as assertions to verify an element's state or behavior.

<figure><img src="/files/IQkCVF2fOPudPO1lliVF" alt=""><figcaption><p>This step asserts that an element with <em>ID</em> '<em>confirmBtnDisabled</em>' exists on the page.</p></figcaption></figure>

***

### Basic selectors&#x20;

As versatile and robust as they are, CSS selectors are at the same time really easy to learn and read. The four most common selector types in practice are ***type***, .***class***, **#*****id***, and ***\[attribute]*** selectors.

<table><thead><tr><th width="330.79998779296875">Selector</th><th>Result</th></tr></thead><tbody><tr><td>input</td><td>selects all <em>&#x3C;input></em> elements</td></tr><tr><td>.typography5</td><td>selects all elements that have <em>typography5</em> class</td></tr><tr><td>#submit-btn</td><td>selects all elements that have <em>id</em> with the value of <em>'submit-btn'</em></td></tr><tr><td>[type="password"]</td><td>selects all elements that have <em>type</em> attribute with the value of <em>'password'</em></td></tr></tbody></table>

*Type* selector can be replaced with a universal **\*** one that matches every element type on the page. It's a wildcard that is too broad and greedy on its own but can be useful when combined with other selectors in certain edge-cases. For example when you don't care about the element type or don't know anything about the element but its position.

<figure><img src="/files/66zkLZsIvWCiK4ySiJqJ" alt=""><figcaption><p>This selector will match the first descendant of the element with <em>main-content</em> class regardless of what this element may be.</p></figcaption></figure>

***

### Compound selectors

It's not uncommon that elements don't have any unique identifiers or attributes, which makes targeting them harder. This is when we need to explore **compound** and **complex** selectors. A **compound selector** combines multiple predicates of a single element, which makes for a more precise and refined selection.

<table><thead><tr><th width="328.39996337890625">Selector</th><th>Result</th></tr></thead><tbody><tr><td>input[type="password"]</td><td>selects all <em>&#x3C;input></em> elements that have <em>type</em> attribute with the value of <em>'password'</em></td></tr><tr><td>button#confirm</td><td>selects all <em>&#x3C;button></em> elements that have <em>id</em> with the value of <em>'confirm'</em></td></tr><tr><td>.prim-color#submit</td><td>selects all elements that have <em>prim-color</em> class and <em>id</em> with the value of <em>'submit'</em></td></tr><tr><td>.secondary[data-testid="affiliateLink"]</td><td>selects all elements that have <em>secondary</em> class and <em>data-testid</em> attribute with the value of <em>'affiliateLink'</em></td></tr></tbody></table>

However, narrowing selectors can also lead to tests becoming more brittle towards DOM changes. So it is recommended to prioritize stable and predictable attributes like `data-testid` over dynamic, auto-generated or position-based ones.

<figure><img src="/files/o7rA4WCqY3AQL12F7o2Z" alt=""><figcaption><p>Ideally, every element in your tests should have its own unique <em>data-testid</em> attribute.</p></figcaption></figure>

***

### Complex selectors

While compound selectors use multiple attributes for enhanced precision, complex selectors include **combinators** and are based on the relationships between elements or DOM hierarchy. Such selectors can also be called positional and are generally not recommended as they can be susceptible to breakage when DOM changes get introduced. However there are cases where we still need them. It may have to do with the lack of unique attributes of the targeted element or the layout itself may be the object of verification.

<figure><img src="/files/tYyVfex4SRhudDjIMkYa" alt=""><figcaption><p>This will match an element that is a child of an element with <em>nav-item</em> class and has <em>href</em> attribute with the value of '/<em>pricing/'</em>.</p></figcaption></figure>

The four main types of **combinators** are:

* descendant combinator `A B` - selects descendant **B** (children, grandchildren, etc.) of parent **A**
* child combinator `A > B` - selects direct descendant **B** (children, NOT grandchildren and further) of parent **A**&#x20;
* next-sibling combinator `A + B` - selects element **B** that immediately follows its sibling **A**
* sibling combinator `A ~ B` - selects element **B** that follows its sibling **A** (not necessarily immediately)

Some typical examples:

| Selector                              | Result                                                                                                                                                                |
| ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| li a                                  | selects all <*a>* elements that are descendants of the <*li>* element                                                                                                 |
| footer > #footer-controls             | selects all **direct** descendants (children) of the *\<footer>* element that have *id* with the value of *'footer-controls'*                                         |
| li + li\[data-testid="ecommerceLink"] | selects all *\<li>* elements that have *data-testid* attribute with the value of '*ecommerceLink*' and which **immediately** follow another *\<li>* element (sibling) |
| div \~ button#confirmBtn              | selects all *\<button>* elements that have *id* with the value of '*confirmBtn*' and which follow *\<div>* element (sibling)                                          |

To summarize, a **simple** selector targets an element by one of its properties `#confirm`&#x20;

A **compound** selector uses multiple properties of an element for more precision `button#confirm`

A **complex** selector puts elements in the context of relationships `#checkout-modal > button#confirm`

***

### Substring search

CSS also possesses a powerful toolkit of **attribute selector operators** for crafting selectors that can match a portion of an attribute. For the majority of cases in testing we will only need these four:

* **(equals) =** - matches the attribute exactly
* **(contains) \*=** - matches a part of the attribute, regardless of its position
* **(starts with) ^=** - matches a part of the attribute at the start of the value
* **(ends with) $=** - matches a part of the attribute at the end of the value

Partial match selectors are incredibly useful for targeting elements when you don’t know the **exact** value but want to match based on patterns — something that can be very handy in numerous automated testing scenarios. For instance, imagine we need to select an *\<img>* element that has just been inserted into DOM and **\[*****src*****]** is its only predictable attribute, but it gets an auto-generated suffix attached at the end, e.g., `<img src="shop-item-bcuk8j002.jpg">`. Since the auto-generated portion can't be predicted, we can use the (starts with) **^=** operator to target this element by the part that is constant.

<figure><img src="/files/I3cdoDCMkgL40Ux45jPm" alt=""><figcaption><p>This will match all <em>&#x3C;img></em> elements that have <em>src</em> attributes starting with '<em>shop-item'</em></p></figcaption></figure>

Here are some more examples:

| Selector                  | Result                                                                                            |
| ------------------------- | ------------------------------------------------------------------------------------------------- |
| \[alt\*="cart-image"]     | selects all elements that have substring '*cart-image'* in their *alt* attribute                  |
| \[for\*="socials-link"]   | selects all elements that have substring '*socials-link'* in their *for* attribute                |
| button\[id$="-mui-14"]    | selects all *\<button>* elements that have *IDs* ending with substring '*-mui-14'*                |
| a\[href^=<https://docs>"] | selects all *\<a>* elements that have *href* attribute starting with substring '*<https://docs>'* |

Even though **class** can be used with this notation `[class*="btn-primary"]`, simply listing dot-separated classes does the same thing and may be easier on the eyes.

<figure><img src="/files/dRVVgmQDksCEU5Kvn4AZ" alt=""><figcaption><p>Both selectors do the same.</p></figcaption></figure>
