[2026] JavaScript DOM Manipulation | Control Web Pages Dynamically

[2026] JavaScript DOM Manipulation | Control Web Pages Dynamically

이 글의 핵심

JavaScript DOM tutorial: select and update elements, events, delegation, forms, and common pitfalls—querySelector, addEventListener, and production-ready patterns.

Introduction

What is the DOM?

The DOM (Document Object Model) represents an HTML document as a tree. JavaScript can manipulate the DOM to change the page dynamically. 아래 코드는 html를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// 실행 예제
<!DOCTYPE html>
<html>
  <head>
    <title>제목</title>
  </head>
  <body>
    <h1 id="title">안녕하세요</h1>
    <p class="content">내용</p>
  </body>
</html>

DOM tree: 아래 코드는 code를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

document
  └─ html
      ├─ head
      │   └─ title
      └─ body
          ├─ h1#title
          └─ p.content

A closer look at the tree

  • document: Entry to the tree. document.documentElement is <html>; document.body is <body>.
  • Node: Not only elements—text and comments are nodes too. In <p>안녕</p>, "안녕" is a text node.
  • Parent, child, sibling: Navigate with parentElement, children, nextElementSibling, etc. (see «Other selection helpers» below).
  • Rendering: The browser parses HTML into a DOM and paints with CSS. Changing the DOM (text, attributes, children) updates what you see. In practice, use the Elements panel in DevTools to inspect structure often.

1. Selecting elements

getElementById

// By id (often fastest)
const title = document.getElementById("title");
console.log(title.textContent);  // 안녕하세요

querySelector / querySelectorAll

다음은 javascript를 활용한 상세한 구현 코드입니다. 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// CSS selector (first match)
const title = document.querySelector("#title");
const content = document.querySelector(".content");
const firstP = document.querySelector("p");
// All matches
const allPs = document.querySelectorAll("p");
console.log(allPs.length);  // number of p elements
// Complex selectors
const link = document.querySelector("div.container > a.link");
const items = document.querySelectorAll("ul li:nth-child(odd)");
// Iterate NodeList
allPs.forEach(p => {
    console.log(p.textContent);
});

Other selection helpers

다음은 javascript를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// By class
const elements = document.getElementsByClassName("content");
// By tag
const paragraphs = document.getElementsByTagName("p");
// Children
const parent = document.getElementById("parent");
const children = parent.children;  // HTMLCollection
const firstChild = parent.firstElementChild;
const lastChild = parent.lastElementChild;
// Siblings
const element = document.getElementById("myElement");
const next = element.nextElementSibling;
const prev = element.previousElementSibling;
// Parent
const parent = element.parentElement;

2. Changing elements

Text

아래 코드는 javascript를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

const title = document.getElementById("title");
// textContent: plain text
title.textContent = "새로운 제목";
// innerHTML: parses HTML (watch XSS!)
title.innerHTML = "새로운 <strong>제목</strong>";
// innerText: visible text (layout-aware)
title.innerText = "제목";

innerHTML vs textContent in production

textContentinnerHTML
ContentPlain text onlyParses HTML strings into the DOM
XSSUser input won’t execute as markupUntrusted strings can inject scripts
CostSimple and safeHTML parse cost + security concerns
Rule: For user input or API text, default to textContent. If you truly need HTML, sanitize first (e.g. DOMPurify). For dynamic lists, createElement + appendChild is often easier to audit than big innerHTML strings.
아래 코드는 javascript를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
// ✅ Safe: text only
el.textContent = userInput;
// ⚠️ Risky: userInput could contain <script>
el.innerHTML = userInput;

Attributes

다음은 javascript를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

const link = document.querySelector("a");
// Read
console.log(link.getAttribute("href"));
// Write
link.setAttribute("href", "https://google.com");
link.setAttribute("target", "_blank");
// Remove
link.removeAttribute("target");
// Direct properties
link.href = "https://google.com";
link.id = "myLink";
link.className = "link active";
// classList
link.classList.add("highlight");
link.classList.remove("active");
link.classList.toggle("selected");  // remove if present, else add
console.log(link.classList.contains("highlight"));  // true

Styles

다음은 javascript를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

const box = document.getElementById("box");
// Inline styles
box.style.color = "red";
box.style.backgroundColor = "yellow";
box.style.fontSize = "20px";
// Multiple at once
Object.assign(box.style, {
    color: "blue",
    backgroundColor: "lightgray",
    padding: "10px",
    borderRadius: "5px"
});
// Computed styles
const styles = window.getComputedStyle(box);
console.log(styles.color);  // rgb(0, 0, 255)

3. Creating and removing elements

Creating

다음은 javascript를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// Create
const div = document.createElement("div");
div.textContent = "새 요소";
div.className = "box";
div.id = "newBox";
div.setAttribute("data-id", "123");
// Append
document.body.appendChild(div);  // at end of body
// Insert at a position
const container = document.getElementById("container");
const firstChild = container.firstElementChild;
container.insertBefore(div, firstChild);  // before first child
// insertAdjacentHTML
container.insertAdjacentHTML("beforeend", "<p>새 단락</p>");
// beforebegin: before element
// afterbegin: before first child
// beforeend: after last child
// afterend: after element

Removing

다음은 javascript를 활용한 상세한 구현 코드입니다. 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

const element = document.getElementById("myElement");
// Option 1: remove()
element.remove();
// Option 2: removeChild()
const parent = element.parentElement;
parent.removeChild(element);
// Clear all children
const container = document.getElementById("container");
container.innerHTML = "";  // simple but does not remove listeners cleanly
// Or
while (container.firstChild) {
    container.removeChild(container.firstChild);
}

Cloning

아래 코드는 javascript를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

const original = document.getElementById("original");
// Shallow (no descendants)
const shallowClone = original.cloneNode(false);
// Deep (with descendants)
const deepClone = original.cloneNode(true);
document.body.appendChild(deepClone);

4. Events

Listeners

다음은 javascript를 활용한 상세한 구현 코드입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

const button = document.getElementById("myButton");
button.addEventListener("click", function(event) {
    console.log("클릭됨!");
    console.log("이벤트 타입:", event.type);
    console.log("타겟:", event.target);
});
// Arrow function
button.addEventListener("click", (e) => {
    console.log("클릭됨!");
});
// Remove listener (same reference)
function handleClick(e) {
    console.log("클릭!");
}
button.addEventListener("click", handleClick);
button.removeEventListener("click", handleClick);
// Run once
button.addEventListener("click", () => {
    console.log("한 번만 실행");
}, { once: true });

Propagation: capturing and bubbling

Events travel the DOM in two phases:

  1. Capturing: window → target (top down).
  2. Target: the element that received the event.
  3. Bubbling: target → window (bottom up). Most events bubble. The third argument to addEventListener controls the capture phase. 아래 코드는 javascript를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
// 변수 선언 및 초기화
const outer = document.getElementById("outer");
const inner = document.getElementById("inner");
outer.addEventListener(
  "click",
  () => console.log("outer 캡처"),
  { capture: true }
);
inner.addEventListener("click", () => console.log("inner 타깃"));
outer.addEventListener("click", () => console.log("outer 버블"));
// Click inner: typical order — outer capture → inner target → outer bubble
  • event.target: the innermost element that originated the event.
  • event.currentTarget: the element the handler is bound to (may be a parent when delegating). Use event.stopPropagation() only when needed—it blocks parent handlers too.

Common events

다음은 javascript를 활용한 상세한 구현 코드입니다. 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// Mouse
element.addEventListener("click", e => {});      // click
element.addEventListener("dblclick", e => {});   // double-click
element.addEventListener("mouseenter", e => {}); // enter
element.addEventListener("mouseleave", e => {}); // leave
element.addEventListener("mousemove", e => {});  // move
// Keyboard
input.addEventListener("keydown", e => {
    console.log("키:", e.key);
    console.log("코드:", e.code);
    
    if (e.key === "Enter") {
        console.log("엔터 입력!");
    }
});
input.addEventListener("keyup", e => {});
input.addEventListener("keypress", e => {});  // deprecated
// Forms
form.addEventListener("submit", e => {
    e.preventDefault();  // block default submit
    console.log("폼 제출");
});
input.addEventListener("input", e => {
    console.log("입력값:", e.target.value);
});
input.addEventListener("change", e => {
    console.log("변경됨:", e.target.value);
});
// Window
window.addEventListener("load", () => {
    console.log("페이지 로드 완료");
});
window.addEventListener("resize", () => {
    console.log("창 크기:", window.innerWidth, window.innerHeight);
});
window.addEventListener("scroll", () => {
    console.log("스크롤 위치:", window.scrollY);
});

Event object

아래 코드는 javascript를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

button.addEventListener("click", (event) => {
    console.log(event.type);  // click
    
    console.log(event.target);       // clicked element
    console.log(event.currentTarget); // element with the listener
    
    console.log(event.clientX, event.clientY);  // viewport
    console.log(event.pageX, event.pageY);      // document
    
    event.preventDefault();
    event.stopPropagation();
});

Event delegation

다음은 javascript를 활용한 상세한 구현 코드입니다. 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// ❌ Listener per row (wasteful for many items)
const items = document.querySelectorAll(".item");
items.forEach(item => {
    item.addEventListener("click", () => {
        console.log("클릭:", item.textContent);
    });
});
// ✅ One listener on parent
const list = document.getElementById("list");
list.addEventListener("click", (e) => {
    if (e.target.classList.contains("item")) {
        console.log("클릭:", e.target.textContent);
    }
});
// Works for new nodes too
const newItem = document.createElement("li");
newItem.className = "item";
newItem.textContent = "새 항목";
list.appendChild(newItem);

5. Practical examples

Example 1: To-do list

다음은 html를 활용한 상세한 구현 코드입니다. 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

<!DOCTYPE html>
<html>
<head>
    <title>To-Do 리스트</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 500px;
            margin: 50px auto;
        }
        .todo-item {
            padding: 10px;
            margin: 5px 0;
            border: 1px solid #ddd;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .completed {
            text-decoration: line-through;
            opacity: 0.6;
        }
        button {
            padding: 5px 10px;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <h1>To-Do 리스트</h1>
    
    <input type="text" id="todoInput" placeholder="할 일 입력">
    <button id="addBtn">추가</button>
    
    <div id="todoList"></div>
    
    <script>
        const input = document.getElementById("todoInput");
        const addBtn = document.getElementById("addBtn");
        const todoList = document.getElementById("todoList");
        
        // Add todo
        function addTodo() {
            const text = input.value.trim();
            
            if (!text) {
                alert("할 일을 입력하세요!");
                return;
            }
            
            const todoItem = document.createElement("div");
            todoItem.className = "todo-item";
            
            const span = document.createElement("span");
            span.textContent = text;
            
            const deleteBtn = document.createElement("button");
            deleteBtn.textContent = "삭제";
            
            todoItem.appendChild(span);
            todoItem.appendChild(deleteBtn);
            todoList.appendChild(todoItem);
            
            input.value = "";
            input.focus();
        }
        
        addBtn.addEventListener("click", addTodo);
        
        input.addEventListener("keypress", (e) => {
            if (e.key === "Enter") {
                addTodo();
            }
        });
        
        // Delegation: complete / delete
        todoList.addEventListener("click", (e) => {
            const todoItem = e.target.closest(".todo-item");
            
            if (e.target.tagName === "SPAN") {
                todoItem.classList.toggle("completed");
            } else if (e.target.tagName === "BUTTON") {
                todoItem.remove();
            }
        });
    </script>
</body>
</html>

Example 2: Tabs

다음은 html를 활용한 상세한 구현 코드입니다. 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

<!DOCTYPE html>
<html>
<head>
    <title>탭 UI</title>
    <style>
        .tabs {
            display: flex;
            border-bottom: 2px solid #ddd;
        }
        .tab {
            padding: 10px 20px;
            cursor: pointer;
            border: none;
            background: none;
        }
        .tab.active {
            border-bottom: 3px solid #007bff;
            color: #007bff;
        }
        .tab-content {
            padding: 20px;
            display: none;
        }
        .tab-content.active {
            display: block;
        }
    </style>
</head>
<body>
    <div class="tabs">
        <button class="tab active" data-tab="tab1">탭 1</button>
        <button class="tab" data-tab="tab2">탭 2</button>
        <button class="tab" data-tab="tab3">탭 3</button>
    </div>
    
    <div id="tab1" class="tab-content active">
        <h2>탭 1 내용</h2>
        <p>첫 번째 탭입니다.</p>
    </div>
    
    <div id="tab2" class="tab-content">
        <h2>탭 2 내용</h2>
        <p>두 번째 탭입니다.</p>
    </div>
    
    <div id="tab3" class="tab-content">
        <h2>탭 3 내용</h2>
        <p>세 번째 탭입니다.</p>
    </div>
    
    <script>
        const tabs = document.querySelectorAll(".tab");
        const contents = document.querySelectorAll(".tab-content");
        
        tabs.forEach(tab => {
            tab.addEventListener("click", () => {
                tabs.forEach(t => t.classList.remove("active"));
                contents.forEach(c => c.classList.remove("active"));
                
                tab.classList.add("active");
                const targetId = tab.getAttribute("data-tab");
                document.getElementById(targetId).classList.add("active");
            });
        });
    </script>
</body>
</html>

Example 3: Modal

다음은 html를 활용한 상세한 구현 코드입니다. 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

<!DOCTYPE html>
<html>
<head>
    <title>모달</title>
    <style>
        .modal {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.5);
            justify-content: center;
            align-items: center;
        }
        .modal.active {
            display: flex;
        }
        .modal-content {
            background: white;
            padding: 30px;
            border-radius: 10px;
            max-width: 500px;
        }
        .close {
            float: right;
            cursor: pointer;
            font-size: 24px;
        }
    </style>
</head>
<body>
    <button id="openModal">모달 열기</button>
    
    <div id="modal" class="modal">
        <div class="modal-content">
            <span class="close">&times;</span>
            <h2>모달 제목</h2>
            <p>모달 내용입니다.</p>
        </div>
    </div>
    
    <script>
        const openBtn = document.getElementById("openModal");
        const modal = document.getElementById("modal");
        const closeBtn = document.querySelector(".close");
        
        openBtn.addEventListener("click", () => {
            modal.classList.add("active");
        });
        
        closeBtn.addEventListener("click", () => {
            modal.classList.remove("active");
        });
        
        modal.addEventListener("click", (e) => {
            if (e.target === modal) {
                modal.classList.remove("active");
            }
        });
        
        document.addEventListener("keydown", (e) => {
            if (e.key === "Escape" && modal.classList.contains("active")) {
                modal.classList.remove("active");
            }
        });
    </script>
</body>
</html>

Example 4: Dynamic list (add/delete)

Build <li> nodes from input; attach delete with createElement or use delegation. Below uses delegation only. 다음은 html를 활용한 상세한 구현 코드입니다. 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

<ul id="itemList"></ul>
<input type="text" id="itemInput" placeholder="항목">
<button type="button" id="addBtn">추가</button>
<script>
  const list = document.getElementById("itemList");
  const input = document.getElementById("itemInput");
  const addBtn = document.getElementById("addBtn");
  function addItem() {
    const text = input.value.trim();
    if (!text) return;
    const li = document.createElement("li");
    li.textContent = text; // text only (avoid HTML injection)
    const del = document.createElement("button");
    del.type = "button";
    del.textContent = "삭제";
    del.dataset.action = "delete";
    li.appendChild(del);
    list.appendChild(li);
    input.value = "";
  }
  addBtn.addEventListener("click", addItem);
  list.addEventListener("click", (e) => {
    const btn = e.target.closest("button[data-action='delete']");
    if (!btn) return;
    btn.closest("li")?.remove();
  });
</script>

Example 5: Client-side form validation

Use HTML5 required, pattern, type=“email” for first-line checks; JavaScript can show messages and manage focus. Always validate again on the server. 다음은 html를 활용한 상세한 구현 코드입니다. 에러 처리를 통해 안정성을 확보합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

<form id="signup" novalidate>
  <label>
    이메일
    <input type="email" id="email" name="email" required>
  </label>
  <span id="emailError" class="error" aria-live="polite"></span>
  <label>
    비밀번호 (8자 이상)
    <input type="password" id="password" name="password" minlength="8" required>
  </label>
  <span id="pwError" class="error" aria-live="polite"></span>
  <button type="submit">가입</button>
</form>
<script>
  const form = document.getElementById("signup");
  const email = document.getElementById("email");
  const password = document.getElementById("password");
  const emailError = document.getElementById("emailError");
  const pwError = document.getElementById("pwError");
  function validateEmailField() {
    emailError.textContent = "";
    if (!email.validity.valid) {
      emailError.textContent = email.validationMessage || "이메일 형식을 확인하세요.";
      return false;
    }
    return true;
  }
  function validatePasswordField() {
    pwError.textContent = "";
    if (password.value.length < 8) {
      pwError.textContent = "비밀번호는 8자 이상이어야 합니다.";
      return false;
    }
    return true;
  }
  email.addEventListener("blur", validateEmailField);
  password.addEventListener("blur", validatePasswordField);
  form.addEventListener("submit", (e) => {
    const okEmail = validateEmailField();
    const okPw = validatePasswordField();
    if (!okEmail || !okPw) {
      e.preventDefault();
      return;
    }
    console.log({ email: email.value });
  });
</script>

6. Forms

Form events

다음은 html를 활용한 상세한 구현 코드입니다. 비동기 처리를 통해 효율적으로 작업을 수행합니다, 에러 처리를 통해 안정성을 확보합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

<form id="myForm">
    <input type="text" id="username" name="username" required>
    <input type="email" id="email" name="email" required>
    <input type="password" id="password" name="password" required>
    <button type="submit">제출</button>
</form>
<script>
    const form = document.getElementById("myForm");
    
    form.addEventListener("submit", (e) => {
        e.preventDefault();  // avoid full page reload
        
        const formData = new FormData(form);
        
        const data = {
            username: formData.get("username"),
            email: formData.get("email"),
            password: formData.get("password")
        };
        
        console.log(data);
        
        const username = document.getElementById("username").value;
        const email = document.getElementById("email").value;
        
        if (username.length < 3) {
            alert("사용자명은 3자 이상이어야 합니다");
            return;
        }
        
        fetch("/api/register", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(data)
        })
        .then(response => response.json())
        .then(result => console.log(result))
        .catch(error => console.error(error));
    });
    
    const username = document.getElementById("username");
    
    username.addEventListener("input", (e) => {
        const value = e.target.value;
        
        if (value.length < 3) {
            username.style.borderColor = "red";
        } else {
            username.style.borderColor = "green";
        }
    });
</script>

7. Common mistakes

Mistake 1: touching the DOM before it exists

아래 코드는 javascript를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// ❌ Runs before HTML is parsed
const button = document.getElementById("myButton");  // null!
button.addEventListener("click", () => {});  // TypeError
// ✅ Wait for DOMContentLoaded
document.addEventListener("DOMContentLoaded", () => {
    const button = document.getElementById("myButton");
    button.addEventListener("click", () => {
        console.log("클릭!");
    });
});
// ✅ Or put <script> at the end of <body>

Mistake 2: clearing innerHTML drops listeners

아래 코드는 javascript를 사용한 구현 예제입니다. 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// ❌ innerHTML rebuilds subtree — listeners are gone
const container = document.getElementById("container");
const button = document.createElement("button");
button.textContent = "클릭";
button.addEventListener("click", () => console.log("클릭!"));
container.appendChild(button);
container.innerHTML = "";  // listeners removed
// ✅ removeChild loop
while (container.firstChild) {
    container.removeChild(container.firstChild);
}

Mistake 3: event bubbling surprises

다음은 javascript를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// Bubbling example
<div id="parent">
    <button id="child">버튼</button>
</div>
document.getElementById("parent").addEventListener("click", () => {
    console.log("부모 클릭");
});
document.getElementById("child").addEventListener("click", (e) => {
    console.log("자식 클릭");
    // e.stopPropagation();
});
// Click button:
// 자식 클릭
// 부모 클릭 (bubble)

8. Practice problems

Problem 1: Counter

Build increment/decrement buttons around a number. 다음은 html를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

<div id="counter">
    <button id="decrease">-</button>
    <span id="count">0</span>
    <button id="increase">+</button>
</div>
<script>
    let count = 0;
    const countSpan = document.getElementById("count");
    
    document.getElementById("increase").addEventListener("click", () => {
        count++;
        countSpan.textContent = count;
    });
    
    document.getElementById("decrease").addEventListener("click", () => {
        count--;
        countSpan.textContent = count;
    });
</script>

Problem 2: Dynamic list

Add items from input and delete them. 다음은 html를 활용한 상세한 구현 코드입니다. 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

<input type="text" id="itemInput">
<button id="addItem">추가</button>
<ul id="itemList"></ul>
<script>
    const input = document.getElementById("itemInput");
    const addBtn = document.getElementById("addItem");
    const list = document.getElementById("itemList");
    
    function addItem() {
        const text = input.value.trim();
        if (!text) return;
        
        const li = document.createElement("li");
        li.innerHTML = `
            ${text}
            <button class="delete">삭제</button>
        `;
        
        list.appendChild(li);
        input.value = "";
    }
    
    addBtn.addEventListener("click", addItem);
    
    input.addEventListener("keypress", (e) => {
        if (e.key === "Enter") addItem();
    });
    
    list.addEventListener("click", (e) => {
        if (e.target.classList.contains("delete")) {
            e.target.parentElement.remove();
        }
    });
</script>

Summary

Key takeaways

  1. Selection:
    • getElementById(): by id
    • querySelector(): CSS selector
    • querySelectorAll(): all matches
  2. Updates:
    • Text: textContent (default), innerHTML (trusted input only)
    • Attributes: getAttribute(), setAttribute()
    • Style: style, classList
  3. Create/remove:
    • Create: createElement()
    • Insert: appendChild(), insertBefore()
    • Remove: remove(), removeChild()
  4. Events:
    • Add: addEventListener()
    • Remove: removeEventListener()
    • Delegation: listen on an ancestor
    • Phases: capturing (capture: true) and bubbling
  5. Event object:
    • event.target: origin element
    • event.preventDefault(): cancel default action
    • event.stopPropagation(): stop propagation

Best practices

  1. ✅ Prefer querySelector for flexibility
  2. ✅ Use delegation for dynamic lists
  3. ✅ Wait for DOMContentLoaded (or place scripts at the bottom)
  4. ✅ Prefer createElement over untrusted innerHTML
  5. ✅ Remove or avoid duplicate listeners when components unmount

Next steps


... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3