Selecting elements relative to a known element is a common requirement in web development. Whether you need to style a previous sibling based on its successor, programmatically access neighboring elements, or build interactive UI components that respond to element relationships, understanding how to traverse the DOM backward is essential. This guide covers both modern CSS techniques and JavaScript approaches for selecting previous elements.
The CSS Solution: The :has() Pseudo-Class
The CSS :has() pseudo-class revolutionized how we select elements in CSS by introducing true relational selectors. Before its widespread adoption, CSS could only select forward--using the adjacent sibling combinator (+) or general sibling combinator (~) to target elements that came after a reference element.
Understanding the :has() Selector
The :has() pseudo-class represents an element if any of the relative selectors passed as arguments match at least one element when anchored against that element. For selecting previous elements, the key insight is that instead of asking "select element A," you ask "select element A when followed by element B."
The syntax follows this pattern: target:has(selector) where selector describes what follows the target. For example, to select an h2 that is immediately followed by an h3, you would write h2:has(+ h3). This reads as "select all h2 elements that have an immediately following h3," which accomplishes what developers have long wanted--a way to style elements based on their successors. As documented in the MDN Web Docs on CSS :has(), this selector enables selection patterns that were previously impossible in pure CSS.
1/* Select h2 immediately followed by h3 */2h2:has(+ h3) {3 margin-bottom: 0.25rem;4}5 6/* Select any element followed by a warning paragraph */7.element:has(+ p.warning) {8 border-left: 3px solid orange;9}10 11/* Select list items followed by another list item */12li:has(+ li) {13 border-bottom: 1px solid #ddd;14}The JavaScript Solution: previousElementSibling Property
While CSS provides powerful selector capabilities, JavaScript offers more programmatic control through the DOM API. The previousElementSibling property returns the element immediately prior to the specified element in its parent's children list, or null if the element is the first in the list. This read-only property has been widely available across browsers since July 2015, making it a reliable choice for element traversal.
Using previousElementSibling in Practice
The previousElementSibling property works on any Element node and returns the nearest preceding sibling element, skipping text nodes and comments. Unlike previousSibling, which returns any node type including text nodes and comment nodes, previousElementSibling returns only Element nodes, making it more predictable for DOM manipulation tasks. The MDN Web Docs on previousElementSibling provide comprehensive documentation with examples showing sibling traversal patterns.
For most DOM manipulation tasks where you want to work with actual HTML elements, previousElementSibling is the preferred choice. This distinction becomes critical when working with inline elements that might contain text, where previousSibling often returns text nodes containing whitespace. Using the Element variants eliminates these whitespace-related surprises and makes your code more predictable.
1// Get the third div and iterate through all previous siblings2const element = document.getElementById("div-03");3let previous = element.previousElementSibling;4 5while (previous) {6 console.log(previous.nodeName);7 previous = previous.previousElementSibling;8}9 10// Safe traversal with optional chaining11const label = inputElement?.previousElementSibling;12 13// Find previous sibling with specific class14function getPreviousWithClass(element, className) {15 let sibling = element.previousElementSibling;16 while (sibling && !sibling.classList.contains(className)) {17 sibling = sibling.previousElementSibling;18 }19 return sibling;20}CSS :has() Approach
Pure CSS solution for styling based on subsequent elements. Automatically responds to state changes without JavaScript event handlers.
JavaScript Approach
Programmatic DOM traversal with predictable performance. Ideal for imperative operations and complex interactive logic.
Browser Support
:has() has Baseline support since December 2023. previousElementSibling is widely available since July 2015.
Performance
CSS :has() triggers style recalculations. JavaScript property access is constant time with no selector matching overhead.
Best Practices for Element Selection
Effective element selection combines the right technique with clean, maintainable code. When using :has(), prefer simple selectors inside the pseudo-class to minimize selector matching complexity. Use the adjacent sibling combinator (+) for precise immediate-previous selection, and reserve the general sibling combinator (~) for cases where any subsequent match is acceptable.
Key Guidelines
- Use :has() for styling that responds to state changes--it automatically updates without JavaScript
- Use JavaScript for imperative operations triggered by user actions or application logic
- Always check for null before using
previousElementSiblingresults - Abstract traversal logic into utility functions for maintainability
Common Patterns
- Form Validation: Use
previousElementSiblingto access labels and error messages for form validation - Accordion Components: Toggle open/close states by accessing previous/next items
- Navigation Menus: Implement keyboard navigation with arrow keys using DOM traversal
- Conditional Styling: Use
:has()for spacing adjustments based on content structure
For complex applications, abstract element traversal logic into utility functions that express intent clearly. A function named getPreviousSection(element) is more readable than inline element.previousElementSibling chains, and it provides a single place to handle any special cases or edge conditions your application might require. Explore our guide on CSS rules and rulesets for deeper insights into selector patterns.
Frequently Asked Questions
Need Help with DOM Manipulation or CSS Selectors?
Our web development team specializes in building performant, accessible web applications using modern techniques and best practices. From [CSS architecture](/services/web-development/) to JavaScript optimization, we help you implement clean, maintainable solutions.
Sources
- MDN Web Docs - CSS :has() - Official CSS selector reference with browser compatibility data and practical examples
- MDN Web Docs - previousElementSibling - Official DOM API documentation with examples showing sibling traversal