The CSS :has() selector is a game-changing feature that finally allows developers to select parent elements based on their children. Often called the "parent selector," this powerful pseudo-class has been one of the most requested CSS features for decades. In this complete tutorial, you'll learn how to use CSS :has() selector with practical, real-world examples.
What is the CSS :has() Selector?
The CSS :has() pseudo-class represents an element if any of the selectors passed as parameters match at least one element when anchored against this element. In simpler terms, it lets you style a parent element based on what it contains.
Before :has(), CSS could only select elements in a top-down fashion — you could style children based on their parents, but never the other way around. The :has() selector reverses this limitation, opening up possibilities that previously required JavaScript.
Basic Syntax
Why is CSS :has() So Important?
The CSS has selector is revolutionary for several reasons:
1. Eliminates JavaScript Dependencies
Many interactive UI patterns that previously required JavaScript event listeners can now be achieved with pure CSS. Form validation states, hover effects on parent elements, and conditional layouts become simpler.
2. Better Performance
CSS-based solutions are typically faster than JavaScript equivalents because they're handled by the browser's rendering engine directly, without the overhead of JavaScript execution.
3. Cleaner Code
Instead of adding and removing classes with JavaScript, you can write declarative CSS rules that automatically apply based on the DOM structure.
4. Progressive Enhancement
Since :has() is now supported in all major browsers, you can use it with confidence while providing fallbacks for older browsers.
Browser Support for CSS :has()
The CSS :has() selector browser support has reached excellent levels in 2025:
- Chrome: 105+ (September 2022)
- Firefox: 121+ (December 2023)
- Safari: 15.4+ (March 2022)
- Edge: 105+ (September 2022)
This means over 95% of global users can experience :has() selector functionality without any issues.
Step-by-Step: Using CSS :has() Selector
Follow these steps to master the CSS :has() pseudo-class and implement it in your projects.
Step 1: Understanding the Basic Syntax
Start by learning the basic syntax of the :has() selector. The pattern is parent:has(child) where the parent element is selected if it contains the specified child.
Step 2: Styling Form Input States
One of the most common uses of :has() is highlighting form containers based on input focus state.
Step 3: Creating Conditional Layouts
Use :has() to change layouts based on content presence, like styling cards differently when they contain images.
Step 4: Combining with Other Selectors
Combine :has() with :not() and sibling selectors for advanced patterns.
Step 5: Building Interactive Components
Create interactive UI components that respond to child element states without JavaScript.
Practical CSS :has() Examples
Let's dive into practical examples that demonstrate the power of the CSS :has() pseudo-class. Each example shows real-world use cases you can implement in your projects today.
Example 1: Form Input States
One of the most common uses of :has() is styling form containers based on input states:
Example 2: Card with Image Detection
Style cards differently based on whether they contain an image:
Example 3: Navigation Active States
Highlight parent menu items when a submenu link is active:
Example 4: Conditional Grid Layouts
Change grid layout based on the number of children:
Example 5: Empty State Handling
Show different content when a container is empty:
Interactive Demo
Below is a complete interactive demo showcasing various CSS :has() selector examples. Interact with the form, buttons, and cards to see how parent elements respond to their children's states — all without a single line of JavaScript!
Advanced CSS :has() Techniques
Combining :has() with Other Selectors
The true power of :has() emerges when combined with other CSS selectors:
Using :has() with Adjacent Sibling Combinator
The :has() selector also works with sibling combinators:
Negating :has() with :not()
Combine :has() with :not() for powerful exclusion patterns:
CSS :has() vs JavaScript: When to Use What
While CSS :has() is powerful, it's not a complete JavaScript replacement. Here's a guide:
Use CSS :has() When:
- Styling based on child element presence
- Form validation visual feedback
- Hover states that affect parent elements
- Layout changes based on content
- Simple toggle states tied to DOM structure
Use JavaScript When:
- You need to modify the DOM
- Complex conditional logic is required
- You need to store or process data
- Animations require precise timing control
- Cross-component state management
Performance Considerations
The CSS :has() selector performance is generally excellent, but keep these tips in mind:
Do's:
- Use specific selectors inside
:has() - Limit the scope with class names
- Combine with structural pseudo-classes
Don'ts:
- Avoid
*:has()(selecting all elements) - Don't nest
:has()too deeply - Avoid overly complex selectors inside
:has()
Common Use Cases for CSS :has()
Here are popular scenarios where the CSS has selector shines:
| Use Case | Description |
|---|---|
| Form Validation | Style containers based on input validity |
| Card Layouts | Adjust layout based on content presence |
| Navigation | Highlight parent menu items |
| Dark Mode | Toggle styles based on checkbox state |
| Quantity Queries | Change layout based on item count |
| Empty States | Show/hide content based on children |
| Media Detection | Style containers with images/videos |
| Accessibility | Enhance focus visibility for parents |
Frequently Asked Questions
What is the CSS :has() selector used for?
The CSS :has() selector is used to select and style parent elements based on their children or descendants. It's commonly called the "parent selector" because it allows styling elements based on what they contain, which was previously impossible in CSS.
Is CSS :has() supported in all browsers?
Yes, as of 2025, CSS :has() is supported in all major browsers including Chrome, Firefox, Safari, and Edge. Global browser support is over 95%, making it safe to use in production.
Can CSS :has() replace JavaScript?
CSS :has() can replace JavaScript for many visual state changes like hover effects, focus states, and conditional styling. However, JavaScript is still needed for DOM manipulation, data processing, and complex logic.
How does :has() affect performance?
CSS :has() performance is generally good when used with specific selectors. Avoid using it with universal selectors (*) or in overly complex combinations. The browser optimizes :has() queries efficiently in most cases.
Can I use :has() with :not()?
Yes! Combining :has() with :not() is very powerful. For example, :not(:has(img)) selects elements that don't contain images, enabling sophisticated conditional styling.
Conclusion
The CSS :has() selector is one of the most significant additions to CSS in recent years. It finally gives developers the ability to select parent elements, enabling patterns that previously required JavaScript. With excellent browser support in 2025, there's no reason not to start using it in your projects.
Key takeaways from this tutorial:
- :has() selects parents based on their children
- Reduces JavaScript for visual state changes
- Works with all combinators (child, sibling, descendant)
- Excellent browser support (95%+ global coverage)
- Great performance when used with specific selectors
Start experimenting with the CSS :has() pseudo-class in your projects. Once you get comfortable with it, you'll wonder how you ever built UIs without it!
Related Tutorials
- Bento Grid Layout with HTML and CSS
- Modern Website UI Design with HTML and CSS
- Responsive Website Layout with HTML and CSS
- Button Hover Effects with HTML and CSS
If you found this CSS :has() selector tutorial helpful, share it with your developer friends and follow Code Info for more web development guides!