Learn to interact with web pages dynamically using JavaScript DOM manipulation. Master element selection, content modification, style changes, event handling, and create interactive web applications.
Learn to interact with web pages dynamically using JavaScript DOM manipulation. Master element selection, content modification, style changes, event handling, and create interactive web applications.
The Document Object Model (DOM) is a programming interface for web documents. It represents the page as a tree structure:
1<!DOCTYPE html>
2<html>
3 <head>
4 <title>My Page</title>
5 </head>
6 <body>
7 <h1 id="title">Welcome</h1>
8 <p class="intro">This is a paragraph.</p>
9 <div>
10 <button>Click me</button>
11 </div>
12 </body>
13</html>JavaScript sees this as a tree of objects you can manipulate:
1// The document object represents the entire page
2console.log(document); // The root document
3console.log(document.documentElement); // <html> element
4console.log(document.head); // <head> element
5console.log(document.body); // <body> element
6console.log(document.title); // "My Page"
7
8// Every HTML element becomes a JavaScript object
9const titleElement = document.getElementById('title');
10console.log(titleElement.tagName); // "H1"
11console.log(titleElement.textContent); // "Welcome"Multiple ways to find elements in the DOM:
1// By ID (returns single element or null)
2const title = document.getElementById('title');
3
4// By class name (returns HTMLCollection - array-like)
5const introElements = document.getElementsByClassName('intro');
6
7// By tag name (returns HTMLCollection)
8const paragraphs = document.getElementsByTagName('p');
9
10// CSS selectors (returns first match or null)
11const firstButton = document.querySelector('button');
12const titleById = document.querySelector('#title');
13const introByClass = document.querySelector('.intro');
14
15// CSS selectors (returns NodeList of all matches)
16const allButtons = document.querySelectorAll('button');
17const allIntroElements = document.querySelectorAll('.intro');
18
19// Modern preferred methods
20const element = document.querySelector('#title'); // Single element
21const elements = document.querySelectorAll('.intro'); // All matchingOnce you have an element, you can read and modify it:
1const heading = document.querySelector('h1');
2
3// Content manipulation
4console.log(heading.textContent); // Text only
5console.log(heading.innerHTML); // HTML content
6console.log(heading.outerHTML); // Element + HTML content
7
8heading.textContent = "New Title"; // Safe text setting
9heading.innerHTML = "<strong>Bold Title</strong>"; // HTML setting
10
11// Attribute manipulation
12console.log(heading.id); // Get id attribute
13heading.id = "main-title"; // Set id attribute
14heading.setAttribute('data-version', '1.0'); // Set custom attribute
15console.log(heading.getAttribute('data-version')); // Get custom attribute
16
17// Class manipulation
18heading.className = "title main"; // Set class string
19heading.classList.add('highlight'); // Add class
20heading.classList.remove('main'); // Remove class
21heading.classList.toggle('active'); // Toggle class
22console.log(heading.classList.contains('title')); // Check classYou can create elements from scratch with JavaScript:
1// Create a new element
2const newDiv = document.createElement('div');
3newDiv.textContent = 'This is a new div';
4newDiv.className = 'generated-content';
5
6// Create elements with attributes
7const newLink = document.createElement('a');
8newLink.href = 'https://example.com';
9newLink.textContent = 'Visit Example';
10newLink.target = '_blank';
11
12// Create more complex structures
13const card = document.createElement('div');
14card.className = 'card';
15card.innerHTML = `
16 <h3>Card Title</h3>
17 <p>Card description goes here.</p>
18 <button>Learn More</button>
19`;Once created, elements need to be added to the page:
1const container = document.getElementById('content');
2
3// Append to end of container
4container.appendChild(newDiv);
5
6// Insert at specific position
7const firstChild = container.firstElementChild;
8container.insertBefore(newLink, firstChild);
9
10// Modern insertion methods
11container.append(newDiv); // Can insert multiple elements/text
12container.prepend(newLink); // Insert at beginning
13container.after(card); // Insert after the container
14container.before(card); // Insert before the container
15
16// Insert adjacent HTML
17container.insertAdjacentHTML('beforeend', '<p>Added via HTML</p>');
18container.insertAdjacentHTML('afterbegin', '<h2>At the start</h2>');Change CSS styles directly with JavaScript:
1const element = document.querySelector('.target');
2
3// Direct style manipulation
4element.style.color = 'red';
5element.style.backgroundColor = 'yellow';
6element.style.fontSize = '18px';
7element.style.display = 'none';
8
9// Multiple styles at once
10Object.assign(element.style, {
11 color: 'blue',
12 padding: '10px',
13 border: '1px solid gray',
14 borderRadius: '5px'
15});
16
17// CSS custom properties (CSS variables)
18element.style.setProperty('--main-color', '#3498db');
19
20// Get computed styles
21const computedStyles = window.getComputedStyle(element);
22console.log(computedStyles.color); // Actual color value
23console.log(computedStyles.fontSize); // Computed font sizeSeveral ways to remove elements from the DOM:
1const elementToRemove = document.querySelector('.old-content');
2
3// Modern method (preferred)
4elementToRemove.remove();
5
6// Traditional method
7elementToRemove.parentNode.removeChild(elementToRemove);
8
9// Remove all children
10const container = document.querySelector('#content');
11container.innerHTML = ''; // Quick but destroys event listeners
12// Better approach:
13while (container.firstChild) {
14 container.removeChild(container.firstChild);
15}
16
17// Or modern approach:
18container.replaceChildren(); // Removes all childrenEvents make web pages interactive by responding to user actions:
1// Basic event listener
2const button = document.getElementById('my-button');
3button.addEventListener('click', function() {
4 alert('Button was clicked!');
5});
6
7// Arrow function syntax
8button.addEventListener('click', () => {
9 console.log('Button clicked');
10});
11
12// Named function (can be removed later)
13function handleClick(event) {
14 console.log('Button clicked', event);
15}
16button.addEventListener('click', handleClick);
17
18// Remove event listener
19button.removeEventListener('click', handleClick);Different events for different user interactions:
1const input = document.querySelector('#username');
2const form = document.querySelector('#signup-form');
3const div = document.querySelector('#hover-area');
4
5// Mouse events
6div.addEventListener('click', e => console.log('Clicked'));
7div.addEventListener('dblclick', e => console.log('Double clicked'));
8div.addEventListener('mouseenter', e => console.log('Mouse entered'));
9div.addEventListener('mouseleave', e => console.log('Mouse left'));
10div.addEventListener('mouseover', e => console.log('Mouse over'));
11
12// Keyboard events
13input.addEventListener('keydown', e => console.log('Key down:', e.key));
14input.addEventListener('keyup', e => console.log('Key up:', e.key));
15input.addEventListener('keypress', e => console.log('Key press:', e.key));
16
17// Form events
18input.addEventListener('focus', e => console.log('Input focused'));
19input.addEventListener('blur', e => console.log('Input lost focus'));
20input.addEventListener('input', e => console.log('Input changed:', e.target.value));
21form.addEventListener('submit', e => {
22 e.preventDefault(); // Prevent default form submission
23 console.log('Form submitted');
24});
25
26// Window events
27window.addEventListener('load', e => console.log('Page loaded'));
28window.addEventListener('resize', e => console.log('Window resized'));
29window.addEventListener('scroll', e => console.log('Page scrolled'));The event object contains useful information:
1button.addEventListener('click', function(event) {
2 console.log('Event type:', event.type); // 'click'
3 console.log('Target element:', event.target); // The clicked element
4 console.log('Current target:', event.currentTarget); // Element with listener
5 console.log('Mouse coordinates:', event.clientX, event.clientY);
6 console.log('Timestamp:', event.timeStamp);
7
8 // Prevent default behavior
9 event.preventDefault();
10
11 // Stop event from bubbling up
12 event.stopPropagation();
13});
14
15// Keyboard event details
16input.addEventListener('keydown', function(event) {
17 console.log('Key pressed:', event.key); // 'a', 'Enter', 'Shift'
18 console.log('Key code:', event.code); // 'KeyA', 'Enter', 'ShiftLeft'
19 console.log('Ctrl pressed:', event.ctrlKey);
20 console.log('Shift pressed:', event.shiftKey);
21 console.log('Alt pressed:', event.altKey);
22});Handle events on multiple elements efficiently:
1// Instead of adding listeners to many buttons
2const buttons = document.querySelectorAll('.action-button');
3buttons.forEach(button => {
4 button.addEventListener('click', handleButtonClick); // Not efficient
5});
6
7// Use event delegation on container
8const container = document.querySelector('#button-container');
9container.addEventListener('click', function(event) {
10 // Check if clicked element is a button
11 if (event.target.classList.contains('action-button')) {
12 handleButtonClick(event);
13 }
14});
15
16// More specific delegation
17document.addEventListener('click', function(event) {
18 // Handle different types of clicks
19 if (event.target.matches('.delete-btn')) {
20 handleDelete(event);
21 } else if (event.target.matches('.edit-btn')) {
22 handleEdit(event);
23 } else if (event.target.matches('.like-btn')) {
24 handleLike(event);
25 }
26});Create dynamic form validation with real-time feedback:
1class FormValidator {
2 constructor(form) {
3 this.form = form;
4 this.errors = {};
5 this.setupValidation();
6 }
7
8 setupValidation() {
9 this.form.addEventListener('submit', (e) => this.handleSubmit(e));
10
11 // Real-time validation on input
12 const inputs = this.form.querySelectorAll('input, textarea, select');
13 inputs.forEach(input => {
14 input.addEventListener('blur', () => this.validateField(input));
15 input.addEventListener('input', () => this.clearFieldError(input));
16 });
17 }
18
19 validateField(field) {
20 const value = field.value.trim();
21 const fieldName = field.name;
22 let error = null;
23
24 // Required field validation
25 if (field.required && !value) {
26 error = `${fieldName} is required`;
27 }
28
29 // Email validation
30 else if (field.type === 'email' && value) {
31 const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
32 if (!emailRegex.test(value)) {
33 error = 'Please enter a valid email address';
34 }
35 }
36
37 // Password validation
38 else if (field.type === 'password' && value) {
39 if (value.length < 8) {
40 error = 'Password must be at least 8 characters';
41 }
42 }
43
44 this.displayFieldError(field, error);
45 return !error;
46 }
47
48 displayFieldError(field, error) {
49 const errorElement = field.parentNode.querySelector('.error-message');
50
51 if (error) {
52 this.errors[field.name] = error;
53 field.classList.add('error');
54 if (errorElement) {
55 errorElement.textContent = error;
56 }
57 } else {
58 delete this.errors[field.name];
59 field.classList.remove('error');
60 if (errorElement) {
61 errorElement.textContent = '';
62 }
63 }
64 }
65
66 clearFieldError(field) {
67 field.classList.remove('error');
68 const errorElement = field.parentNode.querySelector('.error-message');
69 if (errorElement) {
70 errorElement.textContent = '';
71 }
72 }
73
74 handleSubmit(event) {
75 event.preventDefault();
76
77 // Validate all fields
78 const inputs = this.form.querySelectorAll('input, textarea, select');
79 let isValid = true;
80
81 inputs.forEach(input => {
82 if (!this.validateField(input)) {
83 isValid = false;
84 }
85 });
86
87 if (isValid) {
88 this.submitForm();
89 } else {
90 console.log('Form has errors:', this.errors);
91 }
92 }
93
94 submitForm() {
95 // Collect form data
96 const formData = new FormData(this.form);
97 const data = Object.fromEntries(formData);
98 console.log('Form submitted:', data);
99 }
100}
101
102// Usage
103const form = document.querySelector('#contact-form');
104const validator = new FormValidator(form);Create an interactive image gallery:
1class ImageGallery {
2 constructor(container) {
3 this.container = container;
4 this.images = [];
5 this.currentIndex = 0;
6 this.lightbox = null;
7
8 this.init();
9 }
10
11 init() {
12 this.createLightbox();
13 this.setupEventListeners();
14 }
15
16 addImages(imageUrls) {
17 imageUrls.forEach((url, index) => {
18 const img = document.createElement('img');
19 img.src = url;
20 img.alt = `Gallery image ${index + 1}`;
21 img.classList.add('gallery-thumbnail');
22 img.dataset.index = index;
23
24 this.container.appendChild(img);
25 this.images.push(url);
26 });
27 }
28
29 createLightbox() {
30 this.lightbox = document.createElement('div');
31 this.lightbox.className = 'lightbox';
32 this.lightbox.innerHTML = `
33 <div class="lightbox-content">
34 <button class="lightbox-close">×</button>
35 <button class="lightbox-prev">‹</button>
36 <img class="lightbox-image" src="" alt="">
37 <button class="lightbox-next">›</button>
38 <div class="lightbox-counter"></div>
39 </div>
40 `;
41
42 document.body.appendChild(this.lightbox);
43 }
44
45 setupEventListeners() {
46 // Thumbnail clicks
47 this.container.addEventListener('click', (e) => {
48 if (e.target.classList.contains('gallery-thumbnail')) {
49 this.openLightbox(parseInt(e.target.dataset.index));
50 }
51 });
52
53 // Lightbox controls
54 this.lightbox.addEventListener('click', (e) => {
55 if (e.target.classList.contains('lightbox-close') ||
56 e.target.classList.contains('lightbox')) {
57 this.closeLightbox();
58 } else if (e.target.classList.contains('lightbox-prev')) {
59 this.prevImage();
60 } else if (e.target.classList.contains('lightbox-next')) {
61 this.nextImage();
62 }
63 });
64
65 // Keyboard navigation
66 document.addEventListener('keydown', (e) => {
67 if (this.lightbox.style.display === 'flex') {
68 if (e.key === 'Escape') this.closeLightbox();
69 if (e.key === 'ArrowLeft') this.prevImage();
70 if (e.key === 'ArrowRight') this.nextImage();
71 }
72 });
73 }
74
75 openLightbox(index) {
76 this.currentIndex = index;
77 this.updateLightboxImage();
78 this.lightbox.style.display = 'flex';
79 document.body.style.overflow = 'hidden';
80 }
81
82 closeLightbox() {
83 this.lightbox.style.display = 'none';
84 document.body.style.overflow = 'auto';
85 }
86
87 prevImage() {
88 this.currentIndex = (this.currentIndex - 1 + this.images.length) % this.images.length;
89 this.updateLightboxImage();
90 }
91
92 nextImage() {
93 this.currentIndex = (this.currentIndex + 1) % this.images.length;
94 this.updateLightboxImage();
95 }
96
97 updateLightboxImage() {
98 const img = this.lightbox.querySelector('.lightbox-image');
99 const counter = this.lightbox.querySelector('.lightbox-counter');
100
101 img.src = this.images[this.currentIndex];
102 counter.textContent = `${this.currentIndex + 1} / ${this.images.length}`;
103 }
104}
105
106// Usage
107const gallery = new ImageGallery(document.querySelector('.gallery'));
108gallery.addImages([
109 'image1.jpg',
110 'image2.jpg',
111 'image3.jpg'
112]);Create a tabbed interface:
1class Tabs {
2 constructor(container) {
3 this.container = container;
4 this.tabs = container.querySelectorAll('.tab-button');
5 this.panels = container.querySelectorAll('.tab-panel');
6 this.activeIndex = 0;
7
8 this.init();
9 }
10
11 init() {
12 // Setup initial state
13 this.showTab(0);
14
15 // Add click handlers
16 this.tabs.forEach((tab, index) => {
17 tab.addEventListener('click', () => this.showTab(index));
18 });
19
20 // Keyboard navigation
21 this.container.addEventListener('keydown', (e) => {
22 if (e.target.classList.contains('tab-button')) {
23 this.handleKeyboard(e);
24 }
25 });
26 }
27
28 showTab(index) {
29 // Update active tab
30 this.tabs.forEach((tab, i) => {
31 tab.classList.toggle('active', i === index);
32 tab.setAttribute('aria-selected', i === index);
33 });
34
35 // Update active panel
36 this.panels.forEach((panel, i) => {
37 panel.classList.toggle('active', i === index);
38 panel.setAttribute('aria-hidden', i !== index);
39 });
40
41 this.activeIndex = index;
42 }
43
44 handleKeyboard(e) {
45 let newIndex = this.activeIndex;
46
47 if (e.key === 'ArrowLeft') {
48 newIndex = (this.activeIndex - 1 + this.tabs.length) % this.tabs.length;
49 } else if (e.key === 'ArrowRight') {
50 newIndex = (this.activeIndex + 1) % this.tabs.length;
51 } else if (e.key === 'Home') {
52 newIndex = 0;
53 } else if (e.key === 'End') {
54 newIndex = this.tabs.length - 1;
55 }
56
57 if (newIndex !== this.activeIndex) {
58 this.showTab(newIndex);
59 this.tabs[newIndex].focus();
60 e.preventDefault();
61 }
62 }
63}
64
65// Usage
66const tabContainer = document.querySelector('.tabs-container');
67const tabs = new Tabs(tabContainer);Your progress is saved in this browser, on this device only.