Here are concrete code examples showing how selectors and combinators target specific nodes in the DOM tree using JavaScript.

Imagine this HTML structure as our blueprint/instance:

<div id="app" class="container">
  <h1 id="main-header">Welcome to the App</h1>
  
  <div class="card" data-active="true">
    <p class="intro">This is a direct child paragraph.</p>
    <div class="nested-wrapper">
      <p>This is a deeply nested paragraph.</p>
    </div>
  </div>
 
  <p class="sibling-text">First paragraph after the card.</p>
  <p class="sibling-text">Second paragraph after the card.</p>
</div>
 

1. Examples of Selectors

Selectors target elements based on their type, class, ID, or attributes.

  • ID Selector (#): Targets a unique element by its id attribute.
// Selects the <h1> element
const header = document.querySelector('#main-header');
header.style.color = 'navy';
 
  • Class Selector (.): Targets all elements sharing a specific class attribute.
// Selects all elements with the class 'card'
const cards = document.querySelectorAll('.card');
 
  • Type Selector (Tag name): Targets all elements of a specific HTML tag.
// Selects every <p> tag in the entire DOM tree
const allParagraphs = document.querySelectorAll('p');
 
  • Attribute Selector ([...]): Targets elements based on an attribute and its value.
// Selects elements where data-active equals "true"
const activeCard = document.querySelector('[data-active="true"]');
 

2. Examples of Combinators

Combinators define the relationship between selectors to navigate the DOM tree hierarchy.

  • Descendant Combinator (Space ): Finds matching elements anywhere inside an ancestor, no matter how deep.
// Matches BOTH paragraphs (<p class="intro"> and the nested one) 
// because they are both inside .card
const paragraphsInCard = document.querySelectorAll('.card p');
 
  • Child Combinator (>): Finds matching elements that are direct children (one level deep).
// Matches ONLY <p class="intro">. 
// It IGNORES the deeply nested paragraph because it's wrapped inside .nested-wrapper.
const directParagraphs = document.querySelectorAll('.card > p');
 
  • Adjacent Sibling Combinator (+): Finds an element that immediately follows another specific element.
// Matches ONLY the FIRST <p class="sibling-text"> 
// because it sits directly below the .card element.
const immediateNext = document.querySelector('.card + p');
 
  • General Sibling Combinator (~): Finds all sibling elements that appear after a given element.
// Matches BOTH <p class="sibling-text"> elements 
// because they share the same parent and come after .card.
const allFollowingSiblings = document.querySelectorAll('.card ~ p');