AGS Logo AGS Logo

CSS Parent Selector
Using :has()

Stack of rocks on the sea side

Photo by Edvard Alexander Rølvaag on Unsplash

One of the most frequently searched CSS questions on Stack Overflow with 4,283 votes and 3.7 million views is "Is there a CSS parent selector?" (figure 1).

screenshot of stack overflow question showing that it has 4283 votes, 33 answers, and 3.7 million views.
Stack Overflow Question1

Since Stack Overflow answers usually only address the specific use case being presented and not necessarily the overarching technique or reason, let's dig into that question a little bit further. Is there a parent selector in CSS? Technically no, there is no way from a child element to crawl back up the DOM tree to find a parent element. However, that doesn't mean we can't achieve the same result in practice by shifting our point of view.

What we can do is use a selector that checks if an element contains a particular sibling or child using the :has() pseudo-class, and then style either the initial element, sibling, or child accordingly. Having reached baseline compatibility in 2023, :has() is now available across all major browsers, with caniuse reporting it as available to 93.9% of users globally.2

Let's look a at concrete use case to see how we might use :has() in the context of a form. For this example we are going to use a very generic contact form that asks for the person's name, email, and (optionally) phone number, and contains a textarea for the user to describe the nature of their inquiry (listing 1).

Form HTML
<form>
  <div class="input-container">
    <label for="name">Your Name</label>
    <input name="name" id="name" type="text" required maxlength="100">
  </div>
  
  <div class="input-container">
    <label for="email">Your Email Address</label>
    <input name="email" id="email" type="email" required maxlength="100">
  </div>
    
  <div class="input-container">
    <label for="tel">Your Phone Number</label>
    <input name="tel" id="tel" type="tel" maxlength="25">
  </div>
  
  <div class="input-container">
    <label for="message">How can we help you?</label>
    <textarea name="message" id="message" required maxlength="1000">
    </textarea>
  </div>
  
  <div class="actions">
    <button type="submit">Send</button>
    <button type="clear">Clear</button>
  </div>
</form>

Visually, with some basic theme styles added, our form looks as follows (figure 2). What we want to do, programmatically via the CSS, is display a red asterisk (*) before the label text on the required fields.

screenshot of form, not filled out with errors showing for fields that are required
Contact Form

Each of our fields are wrapped in a div with a class of input-container, so we want to select labels that are in a div.input-container that contain an element marked as required as seen in listing 2. We then use the ::before pseudo-element coupled with the content property to insert the asterisk. Figure 3 explains each piece of the selector.

Styling the label based on whether the input container contains an element with a required property
  div.input-container:has(:required) label::before {
    content: "* ";
    color: var(--danger);
  }
div.input-container combines an element and a class selector to look for divs with a class of input-container. :has(:required) is a pseudo class looking for children of the div with class input-container that have a required attribute. :required inside of the :has() pseudo-class is a pseudo-class that selects elements that have an attribute of required. label is an element selector. ::before creates a pseudo-element that is the first child of label.
Required Elements' Label Selector Breakdown

Rather than having to remember to add the asterisk in the HTML every time we have a required element, we can control how these elements are distinguished from optional ones via the CSS (figure 4).

Form with asterisks in front of the labels of the fields that are required

By controlling this distinction in the CSS, if were to change our minds and decide we wanted to highlight the optional fields instead of the required ones (figure 5) by adding the word optional in parentheses after the label, we could edit the CSS and only have to change the code in one place as seen in listing 3.

Styling optional field labels
div.input-container:has(:where(input, textarea):not(:required)) label::after {
  content: " (optional)";
  font-style: italic;
}

To style the optional labels, we start the same way we did previously by looking for the children of divs with a class of input-container however, this time we have to specify that we are looking specifically for input and textarea elements without a required attribute. To avoid inadvertently marking all fields as optional we specify which elements lacking the required attribute we are targeting, because we also have labels inside of our container div which do not have a required attribute. Figure 5 further explains the selector.

div.input-container combines an element and a class selector to look for divs with a class of input-container. :has(:where(input, textarea):not(:required)) is a pseudo class looking for children elements that are either an input or textarea that do not have the required attribute. :where(input, textarea) is a pseudo-class selecting elements that are either an input or a textarea. :not(:required) is a pseudo-class that excludes elements with the required attribute. :required inside of the :not() pseudo-class is a pseudo-class that selects elements that have an attribute of required. label, input, and textarea are element selectors. ::after creates a pseudo-element that is the last child of label.
Optional Elements' Label Selector Breakdown

Figure 6 shows the form with the updated selector.

Form with (optional) after the labels of the fields that are optional

The code presented in this article can be found below or on Codepen.

Now you know how to build a selector that checks an element without selecting that element. Let me know what cool stuff you build with this technique.

Happy Coding!


1 Stack Exchange Inc. “Frequent 'css' Questions.” stack overflow, https://stackoverflow.com/questions/tagged/css?tab=Frequent. Accessed 9 February 2025.

2 Deveria, Alexis. “Can I use :has?” caniuse, https://caniuse.com/?search=%3Ahas. Accessed 9 February 2025.

Professional Training

While we build and manage products for ourselves and our clients, we also provide training and coaching for other software and product teams.

License: CC BY-NC-ND 4.0 (Creative Commons)