Hero Background

Next-Gen App & Browser Testing Cloud

Trusted by 2 Mn+ QAs & Devs to accelerate their release cycles

Next-Gen App & Browser Testing Cloud

Test your website on
3000+ browsers

Get 100 minutes of automation
test minutes FREE!!

Test NowArrowArrow

KaneAI - GenAI Native
Testing Agent

Plan, author and evolve end to
end tests using natural language

Test NowArrowArrow
  • Home
  • /
  • Blog
  • /
  • A Guide To Newly Supported CSS Pseudo-Class Selectors
TestMu AI ExperimentsTutorial

A Guide To Newly Supported CSS Pseudo-Class Selectors

In this detailed guide, learn how to leverage CSS pseudo-class selectors in web projects and make your website stand out from the crowd.

Author

Tahera Alam

January 10, 2026

Have you ever wondered how websites add that extra layer of style to certain buttons when they’re hovered over, or change the color of visited links? The secret lies in the power of CSS pseudo-class selectors!

But, before you dismiss this as just another mundane guide on CSS Selectors, let me tell you: we are not doing that here.

Pseudo-classes like hover have been around for a long time. I promise not to bore you by discussing them for the 1000th time. We will instead discuss the powerful modern pseudo-class selectors that you may not be familiar with yet.

Before we deep dive into CSS pseudo-class selectors, if you are unfamiliar with the hover pseudo-class or even what a pseudo-class is, let’s do a quick recap.

Pseudo-class selectors in CSS are selectors that define a special state of an element. They start with the colon character(:) and allow you to apply styles based on the interaction or behavior of the element. For example, you can use CSS pseudo-class selectors to style an element when users hover their mouse over it.

Here’s an example of the :hover pseudo-class:

button:hover{
 background-color: blue;
}

Wondering what’s different about the modern CSS pseudo-class selectors? They play a crucial role in user experience and accessibility. Their ability to target specific elements based on their state allows us to create interactive user interfaces that are inclusive and accessible to all users, including those with impairments.

While they offer immense power, they also come with their drawbacks. It’s critical to consider cross browser compatibility while using them. For example, some selectors may not be fully supported by specific browsers, so it’s crucial to have fallback options in place to ensure that all users have a consistent experience, regardless of their device or browser.

In this guide, I’ll dive into the modern CSS pseudo-class selectors, providing the knowledge you need to use them in your next project and make your website stand out. In addition, it will give you the knowledge you need to take your CSS skills to the next level.

So, let’s get started!

What are Modern CSS pseudo-class selectors?

Modern pseudo-class selectors are a set of new selectors that have been added to the CSS specification in recent years. They offer a range of new and advanced features compared to the older pseudo-class selectors.

Some features include targeting elements based on their relationship to others or selecting elements based on more complex conditions.

These modern CSS pseudo-class selectors bring a level of advanced styling to the table that was not possible earlier.

Deep dive into CSS pseudo-class selectors

In this guide section, we will explore the different CSS pseudo-class selectors. Let’s look at them one by one.

:focus-visible pseudo-class

Before we talk about :focus-visible, I will discuss a common accessibility violation. I am sure you’re aware that it’s a common practice among developers to remove the outlines of interactive elements such as form inputs, buttons, and links during their focus state.

input:focus {
  outline: none;
}

Now, the issue is that the visible focus state is critically important for users who use the keyboard to navigate.

When a user navigates an interface using the keyboard (e.g., by pressing the tab key), a visible focus state can act as a way-finding tool, helping the user understand which element currently has keyboard focus. This can be especially important for users with difficulty using a mouse or other pointing device and those with cognitive or visual impairments. To know the importance of web accessibility, read our tutorial on accessibility testing.

When we set outline none, it significantly degrades the interface’s usability, which we don’t want. That’s where :focus-visible comes in.

The :focus-visible pseudo-class is used to ensure that the focus ring (outline) is only visible when it is needed. It was designed to distinguish between “implicit,” and “explicit” focus, where mouse clicks are considered “implicit” focus, and keyboard navigation is considered “explicit” focus. It uses heuristics, a set of rules and procedures the browser uses to determine when to show the focus ring.

For example, when you tab into an interactive element using a keyboard, the browser will apply the :focus-visible styles. But, if you click the element with a mouse, the browser will not apply the :focus-visible styles.

However, there are some exceptions, like text inputs and text areas, which should show the :focus-visible styles for all focus input types. This makes the focus ring consistent with the user’s expectation and helps reduce the visual noise and improve accessibility.

Enough explanation, right? Let’s look at an example to understand this better.

HTML:

<div class="links">
      <a href="#">LambdaTest</a>
      <a href="#">Features</a>
      <a href="#">Blogs</a>
  </div>

CSS:

a:focus-visible {
  background-color:#ddd;
}

In this example, we have three links, and we asked the browser to apply a background color (in this case #ddd) when any of the links are in focus. Notice if you click them using a mouse pointer, the style doesn’t get applied because the element does not receive the focus-visible status since it’s an implicit click.

But, if you click them using the tab, the background color does get applied because the element receives the focus-visible status since the click is explicit.

Let’s see how our example would function with TestMu AI’s Real Time Testing.

example-with-Real-Time-Testing

:focus-within pseudo-class

The :focus-within pseudo-class in CSS allows you to apply styles to a parent element when one of its child elements is in focus. Imagine you have a form with multiple input fields, the :focus-within pseudo-class allows you to highlight the entire form container (the parent element) when one of the input fields (child element) is selected and in focus.

A practical application of the :focus-within pseudo-class is to style a form label when its associated input field has focus. To achieve this, you can wrap the label and input in a container element, then apply the :focus-within pseudo-class to that container. This allows you to select the label and apply styles when the associated input field is in focus.

Let’s look at an example of that.

HTML:

<div class="form-group">
      <label for="name">Name:</label>
      <input type="text" id="name" />
 </div>

CSS:

.form-group:focus-within label {
  color: #2196f3;
}

In this example, we have a form with a single input field for the user’s name. The label and input are wrapped in a container element with a class of .form-group. We then use :focus-within on the .form-group container to tell the browser that when the input of that container is in focus, change the color of the label to blue.

:is() pseudo-class

The :is() CSS pseudo-class function (formerly called :matches() :any()) takes a list of selectors as its argument and selects any element that can be selected by one of the selectors in that list. This allows for more concise writing when selecting multiple elements and helps make your code more readable.

For example, instead of targeting each heading element individually, you can target a group of headings using :is(h1, h2, h3).

The :is() selector list has unique features that set it apart from other selectors. One of its coolest features is that even if one selector in the list is invalid, the rule will still apply to the valid selectors. This means you can group multiple selectors without worrying about the whole rule breaking just because of one small mistake.

Another important thing to note is that the rule’s specificity will match that of the selector with the highest specificity in the list. For example, a rule using :is(#id, p) will have the same specificity as the #id selector, while a rule using :is(p, a) will have the same specificity as the selector.

Let’s look at an example of this.

HTML:

<h1>LambdaTest</h1>
 <h2>Cross-browser testing platform</h2>
 <h3>Automated testing solution</h3>

CSS:

/* Apply styles to h1, h2, and h3 elements */
:is(h1, h2, h3) {
  font-weight: bold;
  color: purple;
}

In this example, the :is(h1, h2, h3) selector matches all h1, h2, and h3 elements and applies the styles of font-weight: bold and color: purple to them.

:where() pseudo-class

The :where() pseudo-class function takes a list of selectors as an argument and selects elements that can be selected by any of the selectors in that list.

It is almost similar to :is() except for one difference. The difference between :where() and :is() lies in their specificity. :where() always has a specificity of 0, whereas :is() gets the specificity of the most specific selector in its argument list.

Let’s look at an example to see how :where() works.

HTML:

<div class="container">
  <img   src="https://images.unsplash.com/photo-1674530493752-719b5514a7f2?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHx0b3BpYy1mZWVkfDQ2fGJvOGpRS1RhRTBZfHxlbnwwfHx8fA%3D%3D&auto=format&fit=crop&w=600&q=60
"alt=""/>
  </div>

CSS:

:where(img) {
  border: 10px solid blue;
}
img {
  border: 10px solid orange;
}

In this example, we select the image using :where() pseudo-class and add a blue border to it. Then, we again select the image using the img selector and set an orange border. Since :where() has 0 specificity, the second style wins, resulting in the orange border of the image.

The following is an example of implementing :where() using TestMu AI’s Real Time Testing feature.

Real Time Testing feature

:not() pseudo-class

The :not() CSS pseudo-class selector matches elements that do not match a given selector. It means you can exclude specific elements from a selection of elements. The syntax is :not(selector), where the (selector) is the selector to be excluded.

For instance, p:not(.main) matches all < p > elements that don’t have the class main.

HTML:

<div class="container">
        <h1>LambdaTest</h1>
        <p>
          The ultimate cloud-based cross-browser testing platform. Test on over
          3000 browsers, devices, and OS.
        </p>
        <p>Accelerate your GTM with powerful cloud testing.</p>
        <p class="main">
          Integrate <a href="https://www.lambdatest.com/">LambdaTest</a> with
          your favorite tools for seamless testing.
        </p>
      </div>

CSS:

p {
  font-weight: bold;
  color: blue;
}
/* Select all elements except the ones with .main class */
p:not(.main) {
  font-weight: normal;
}

In this example, we have three paragraph tags: first, we apply blue color and bold font-weight to all paragraphs with the p selector. Then, we use the :not() pseudo-class to exclude the last p element that has the .main class from receiving normal font-weight and keep its bold font-weight as set by the p selector.

:has() pseudo-class

The :has() pseudo-class is unique and something we never had in CSS. It’s like a detective on a mission to find specific elements based on the clues of their descendants.

Imagine you have an HTML document with a list of items, and you want to give a unique style to those items that have an extra emphasis, represented by a span element. How can you achieve that? Yes, the answer is :has() pseudo-class.

The :has() pseudo-class allows you to select elements based on whether they have a certain descendant element. Isn’t it fascinating? Let’s take a closer look with an example.

HTML:

<ul>
   <li>Item 1</li>
   <li>Item 2 <span>with emphasis</span></li>
   <li>Item 3</li>
 </ul>

CSS:

li:has(span) {
  font-weight: bold;
  background-color: yellow;
}

In this example, the :has() pseudo-class selects the li elements that have a span descendant. When it finds a match, it applies the styles of font-weight and background-color, making the text bold and the background yellow.

Note that this example may not work for you on a Firefox browser. However, we have an interesting workaround just for you in the browser compatibility section.

:empty pseudo-class

The :empty pseudo-class in CSS selects elements that have no children, including text nodes. This means that an element that has only white space will also be selected by the :empty pseudo-class.

This comes in handy in certain scenarios. For example, you have a div in which you dynamically add content using JavaScript. When content gets appended, you want the div to have some padding and background, but if there’s no content, you don’t want it to take any space on the page. You can very simply hide that div using the :empty pseudo-class.

HTML:

<div>Since the below div element is empty, :empty() pseudo-class selects and hides it.</div>
<div></div>

CSS:

div {
  background-color: orange;
  padding: 10px;
  text-align: center;
}
/* Select the empty div element */
div:empty {
  display: none;
}

:placeholder-shown pseudo-class

The :placeholder-shown pseudo-class in CSS is used to select and style an < input > or < textarea > element that is currently displaying placeholder text.

The :placeholder-shown pseudo-class provides a convenient way to style the placeholder text in a specific way, separate from the other styles of the input element. This allows us to create more intuitive and user-friendly forms by improving the visual cues for placeholder text.

Let’s look at an example.

HTML:

<form>
      <label for="name">Name:</label>
      <input name="name" type="text"placeholder="Your name">
      
      <label for="email">Email Address:</label>
      <input name="email" type="email" placeholder="[email protected]">
 
   </form>

CSS:

input:placeholder-shown {
  background-color: #ddd;
  border: 2px solid orange;
  border-radius: 4px;
}

In this example, we have a form with three input fields for name, email, and age. Each input has a placeholder text. We used input:placeholder-shown CSS pseudo-class to style the input fields that are currently displaying placeholder text. When a user begins to type into an input field, the placeholder text will be replaced by the user’s input, and the styles will no longer apply.

...

:read-only pseudo-class

As the name suggests, the :read-only CSS pseudo-class represents an element that is not editable by the user, meaning its value cannot be changed. This selector can be used to apply styles to elements that have the readonly attribute or have been dynamically set to be read-only through JavaScript.

Following is an example of the same.

HTML:

<form>
      <label for="name">Name:</label>
      <input name="name" type="text"placeholder="Your name"readonly>
      
      <label for="email">Email Address:</label>
      <input name="email" type="email" placeholder="[email protected]">
 
   </form>

CSS:

input:read-only {
  background-color: #ddd;
  border: 1px solid gray;
  pointer-events: none;
}

In the example, the first input that has the readonly attribute is selected by the :read-only pseudo-class selector and the specified styles only gets applied to that element.

The :read-only CSS pseudo-class removes all the styling that makes the inputs look like clickable fields, making them look like read-only paragraphs.

read-write pseudo-class

The :read-write pseudo-class matches elements that are either editable or have the contenteditable attribute set to true.

Some HTML elements, such as input and textarea, are editable by default, but others, such as div and p, are not. The contenteditable attribute can be added to any element to make it editable. The :read-write pseudo-class allows us to specify styles specifically for editable elements, whether they are editable by default or made editable with the contenteditable attribute.

Below is an example.

HTML:

<div contenteditable="true">This is an editable div.</div>

CSS:

div[contenteditable="true"]:read-write {
  background-color: lightgreen;
}

In this example, the :read-write pseudo-class will match the div element with the contenteditable attribute set to true, and the background-color gets applied. It also works for elements that are editable by default, such as inputs and textareas.

:indeterminate pseudo-class

The :indeterminate pseudo-class targets specific form elements, such as checkboxes and radio buttons, as well as progress elements, that are in an intermediate or indeterminate state.

For example, an < input type="checkbox" > can be set to an indeterminate state through JavaScript by setting its indeterminate property to true. Similarly, radio buttons can be considered indeterminate when all buttons with the same name value in the form are unchecked. And < progress > element can be set to an indeterminate state if it doesn’t have a defined value or progress status.

Below is an example for each of them.

  • :indeterminate CSS pseudo-class with a checkbox
    HTML:
  • <input type="checkbox" id="checkbox" />
     <label for="checkbox">Check me</label>
    

CSS:

    input[type="checkbox"]:indeterminate + label {
      color: red;
    }
    

In this example, we created a checkbox input with an id of checkbox and a label that says “Check me.” The JavaScript code sets the indeterminate property of the checkbox to true, which makes the checkbox appear in an indeterminate state. In CSS, we used the :indeterminate pseudo-class to select the checkbox and its adjacent label and set the color of the label to red.

  • :indeterminate CSS pseudo-class with a radio button
    HTML:
  • <form>
          <input type="radio" name="LambdaTestFeatures" id="LambdaTestFeatures" />
          <label for="webTesting">Web testing</label>
          <input type="radio" name="webTesting" id="webTesting" />
          <label for="cypressTesting">Cypress testing</label>
          <input type="radio" name="seleniumTesting" id="seleniumTesting" />
          <label for="selen
    

CSS:

input[type="radio"]:indeterminate + label {
  color: red;
}

In this example, all the radio buttons are in an indeterminate state because none of them have been selected yet. We use the :indeterminate pseudo-class to target the label for each radio button and change its color to red. When a radio button is selected, it no longer matches the :indeterminate selector, and the label returns to its default color.

  • :indeterminate CSS pseudo-class with a progress element
    HTML:
  • <progress></progress>
    

CSS:

progress:indeterminate {
  width: 50vw;
  height: 30px;
}

In this example, the :indeterminate CSS pseudo-class selects the progress element and applies specified styles to it because it has no value and is in an indeterminate state.

Browser compatibility of CSS pseudo-class selectors

Let’s talk about one of the most important aspects of modern web design, i.e., browser compatibility. All your fancy and shiny CSS features are useless if the user’s browser doesn’t support them. That’s why you need to keep browser compatibility in mind.

In this section, we will look at the browser support of all the CSS pseudo-class selectors discussed.

Additionally, to run browser compatibility tests of the CSS features, you can use a cloud-based platform like TestMu AI that offers an online browser farm of numerous real browsers and operating systems combinations to test your websites (and web apps). It lets you perform tests at scale to detect cross browser compatibility issues in HTML/CSS and fix them so that your website or web app works seamlessly across different browsers & OS combinations.

Note

Note: Perform browser compatibility testing across 3000+ real browsers. Try TestMu AI Now!

:focus-visible

The :focus-visible CSS pseudo-class is supported in Chrome from version 86. In Firefox, it is supported from version 4 to 84 using the prefix -moz- and fully supported from version 85.

focus-visible CSS Pseudo-Class Selectors

:focus-within

Here’s an image illustrating the support for the focus-within pseudo-class across different browser versions.

focus-within pseudo-class

:is()

The :is() CSS pseudo-class is supported in Chrome from version 88, and Firefox supports it from version 78.

is CSS pseudo-class

:where()

The :where() pseudo-class is supported in Chrome from version 88 and in Firefox from version 78.

where() pseudo-class

:not()

The :not() CSS pseudo-class is supported in Chrome from version 88. Firefox has support for it from version 84 and Opera from version 75.

Here’s an image that showcases the browser support for this property.

not() CSS pseudo-class

:has()

The :has() CSS pseudo-class selector is supported in some modern browsers, with Chrome offering support from version 105 and Safari from version 15.4.

Note that earlier versions of Firefox (2-102) do not support the :has CSS pseudo-class. However, you can enable this powerful feature as an experimental option in version 103 and later by simply flipping the layout.css.has-selector.enabled flag to true.

Here is an excellent demo inspired from this CodePen example to demonstrate the implementation of :has pseudo-class in Firefox 103 and later:

CSS:

figure:has(figcaption) img {
  outline: 10px dashed red;As we know, the :has pseudo-class isnt supported in Firefox by default. So, you need to enable it to see the demo in action. 


}

In the given example, the :has() CSS pseudo-class targets any figure element that has a figcaption within it. In the HTML document, we have a figure element with a figcaption, so the browser correctly identifies the matching figure element and applies the red border.

To enable it, search for about:config in your Firefox address bar and hit Enter.

has() CSS pseudo-class

Finally, search for layout.css.has-selector.enabled and turn it to true.

layout.css.has-selector.enabled

Congratulations! You just enabled the powerful :has selector support in your Firefox browser.

has selector support

:empty()

The :empty() CSS pseudo-class selector is widely supported in modern browsers, with Chrome offering support from version 4, Safari from version 3.1, and Firefox from version 2.

empty() CSS pseudo-class

:placeholder-shown

The :placeholder-shown CSS pseudo-class is supported in Chrome from version 47. In Firefox, it is partially supported from version 4 to 50 using the prefix -moz-placeholder (instead of placeholder-shown) and fully supported from version 51.

:placeholder-shown

:read-only and read-write

The read-only and read-write pseudo-classes are partially supported in Chrome from version 15 to 35, with support limited only to inputs and textarea fields and not elements with contenteditable attribute. But from version 36, these selectors are fully supported. Similarly, Safari has support from versions 4 to 8 only for inputs and textarea fields and supports fully from version 9.

Firefox supports them from version 3 to 77 using the prefix -moz and fully supports from version 78.

:read-only and read-write

:indeterminate

The :indeterminate CSS pseudo-class has partial support in Chrome from version 15-38 with limitations in selecting radio buttons. It won’t select radio buttons if the group of radio buttons doesn’t have a checked option.

Similarly, Firefox version 4-50 doesn’t support radio buttons. Additionally, version 4-5 doesn’t support the < progress > element.

Chrome has full support from version 39 and Firefox from version 51.

:indeterminate

Wrapping up

As a web designer or developer, you understand the value of constantly learning and exploring new techniques. The introduction of newly supported CSS pseudo-class selectors opens up a world of possibilities to create stunning, interactive, and engaging web experiences. In this guide, we’ve taken a closer look at selectors such as :has(),:any-link(), and :focus-visible, etc., which are at the forefront of modern CSS design.

It’s important to stay updated about the latest browser support for these selectors and to experiment with different ways to incorporate them into your work. Whether you’re building a simple website or a complex web application, these selectors can add an extra layer of style and interactivity to your web projects.

I hope this guide has been helpful to you and has inspired you to use CSS pseudo-class selectors in your designs. So, go ahead, dive in, and let your creativity run wild!

Until then, Happy Styling!

Austin Siewert

Austin Siewert

CEO, Vercel

Discovered @TestMu AI yesterday. Best browser testing tool I've found for my use case. Great pricing model for the limited testing I do 👏

2M+ Devs and QAs rely on TestMu AI

Deliver immersive digital experiences with Next-Generation Mobile Apps and Cross Browser Testing Cloud

Author

Tahera is a freelance Frontend Developer and Technical Writer with over 2 years of hands-on experience in JavaScript, React, Next.js, TypeScript, Tailwind CSS, and Git/GitHub. She specializes in building responsive user interfaces and writing clear, engaging documentation, tutorials, and API guides on technologies like Selenium, Cypress, and modern web development. Tahera has contributed to open-source projects focused on improving UI components and documentation. She has built a following of 7,000+ on X, with some of her posts reaching 400,000+ views, showcasing her influence in the frontend and tech writing community. She currently collaborates with clients on web development and long-form technical content. Although her academic background is in Polity & IR (Bachelor’s) and English Literature (Master’s), she has built her technical expertise through continuous learning and real-world projects.

Frequently asked questions

Did you find this page helpful?

More Related Hubs

TestMu AI forEnterprise

Get access to solutions built on Enterprise
grade security, privacy, & compliance

  • Advanced access controls
  • Advanced data retention rules
  • Advanced Local Testing
  • Premium Support options
  • Early access to beta features
  • Private Slack Channel
  • Unlimited Manual Accessibility DevTools Tests