HTML
CSS
Web Development
Programming
Code Tutorials

How to find elements by class

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Finding DOM elements by class is a core task for event wiring, UI state updates, and client-side rendering logic. Modern browsers provide multiple APIs, but they differ in selector power and collection behavior. Choosing the right API for each context prevents subtle bugs in dynamic interfaces.

getElementsByClassName and Live Collections

getElementsByClassName returns a live HTMLCollection, meaning it updates automatically as DOM changes.

html
1<ul>
2  <li class="item">A</li>
3  <li class="item">B</li>
4</ul>
5<script>
6  const items = document.getElementsByClassName("item");
7  console.log(items.length);
8</script>

Live behavior can be helpful, but it can also surprise you if elements are added or removed during iteration.

querySelectorAll and Static Snapshots

querySelectorAll accepts CSS selectors and returns a static NodeList.

javascript
1const cards = document.querySelectorAll(".card");
2cards.forEach((el) => {
3  el.classList.add("active");
4});

Static snapshots are often easier to reason about in modern component code.

Scope Queries to a Container

Global queries can accidentally match unrelated elements. Scope selection to known parent containers.

javascript
const panel = document.querySelector("#settings-panel");
const toggles = panel.querySelectorAll(".toggle-item");

Scoped queries improve maintainability and can reduce query cost in large pages.

Handle Dynamic DOM with Event Delegation

If elements appear after initial render, per-element listeners are fragile. Event delegation on a stable parent is usually better.

javascript
1document.addEventListener("click", (event) => {
2  const button = event.target.closest(".delete-btn");
3  if (!button) return;
4  button.closest(".row")?.remove();
5});

Delegation handles dynamically inserted elements without re-binding listeners.

Multiple-Class and Advanced Selectors

Class matching can combine conditions using CSS selector syntax.

javascript
const primaryButtons = document.querySelectorAll(".btn.primary");
const visibleCards = document.querySelectorAll(".card:not(.hidden)");

Use expressive selectors for clarity, but keep them readable and consistent with your naming conventions.

Convert Collections for Predictable Iteration

If you need stable iteration while DOM mutates, convert live collections to arrays first.

javascript
const live = document.getElementsByClassName("item");
const snapshot = Array.from(live);
snapshot.forEach((el) => el.classList.add("processed"));

This avoids mutation-related iteration surprises.

Timing Matters in Framework Apps

In React, Vue, or similar frameworks, querying classes too early can return zero matches because component mount is not complete. Prefer framework refs and lifecycle hooks when possible, and use direct DOM queries only for interoperability with third-party widgets.

Keep direct query logic minimal in state-driven architectures.

Debugging Missing Matches

When selectors fail unexpectedly, verify:

  1. selector syntax includes dot prefix for classes
  2. query runs after DOM is available
  3. scope container is correct
  4. class names are not changed by runtime rendering logic
javascript
console.log(document.querySelectorAll(".card").length);

Simple count checks often reveal timing or naming mistakes quickly.

Dynamic DOM Monitoring

In highly dynamic pages, you can combine class queries with MutationObserver to react when nodes are inserted or removed. This is useful for analytics widgets and extension scripts that cannot control render timing directly. Keep observer scope narrow to avoid unnecessary overhead.

Test Stability and Selector Strategy

In automated tests, classes used for styling can change frequently. Consider dedicated test selectors for critical flows, while still using class queries for runtime behavior where appropriate. This reduces brittle failures when design refactors rename visual classes.

Common Pitfalls

  • Assuming getElementsByClassName is static when it is live.
  • Querying entire document repeatedly in hot loops.
  • Forgetting class selector dot in querySelectorAll.
  • Binding events to dynamic elements instead of using delegation.
  • Mixing inconsistent class naming conventions across CSS and JavaScript.

Summary

  • Use querySelectorAll for flexible CSS selectors and static snapshots.
  • Use getElementsByClassName when live collection behavior is desired.
  • Scope queries to container elements for safer selection.
  • Use event delegation for dynamic content.
  • Keep selector strategy consistent with your UI architecture.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.