이벤트는 특정 상황이 발생했음을 알려주는 신호입니다.
웹 페이지에서 발생하는 이벤트에는 click, input, keydown 과 같은 사용자 입력 이벤트뿐 아니라, 이미지 로드 완료(load), 네트워크 요청 실패(error)처럼 브라우저 동작과 관련된 이벤트도 있습니다.
이벤트를 처리하려면 HTML 요소에 이벤트 리스너(Event Listener)를 등록해야 합니다.
부모 요소와 자식 요소가 각각 이벤트를 가지고 있다면, 겹쳐진 영역에서 자식 요소를 클릭했을 때 어떤 순서로 이벤트가 실행될까요?
브라우저는 다음과 같은 3단계 흐름에 따라 이벤트를 전달합니다.
1. 캡처링 단계 (Capturing Phase) – 최상위 요소에서 시작해 타겟 요소까지 위에서 아래로 이벤트를 전달
2. 타겟 단계 (Target Phase) – 이벤트가 실제로 발생한 요소에서 리스너 실행
3. 버블링 단계 (Bubbling Phase) – 타겟에서 다시 최상위 요소까지 아래에서 위로 이벤트를 전달

최상위 요소(Document)에서 이벤트가 시작해, 하위 요소들을 거쳐 최종 타겟 요소까지 전달됩니다.
캡처링은 실무에서 자주 사용되지는 않지만, 보안/필터링 목적, 하위 요소 변경 전에 사전 처리와 같은 상황에서 활용될 수 있습니다.
document.body.addEventListener('click', (e) => {
console.log('캡처링: 클릭을 미리 감지');
}, { capture: true });
이벤트가 실제로 발생한 요소(타겟)에 도착해, 해당 요소에 등록된 이벤트 리스너가 실행됩니다.
타겟에서 시작해 상위 요소로 이벤트가 거꾸로 전파됩니다.
이 과정에서 상위 요소에 등록된 이벤트 리스너가 순서대로 실행됩니다.

HTML 문서는 DOM으로 변환되면 부모-자식 관계를 가진 계층적 트리(Tree) 구조를 형성합니다.
HTML
├─ HEAD
└─ BODY
├─ DIV
└─ P
└─ "Hello"
이벤트 전파 구조는 다음과 같은 장점을 가집니다.
이벤트가 발생한 위치와 그 상위/하위 요소의 반응을 확인하려면, DOM 트리를 위 또는 아래 방향으로 탐색하는 것이 가장 효율적입니다.
캡처링 단계: 이벤트가 타겟에 도착하기 전에 차단하거나 가로채서 처리 가능
버블링 단계: 하위 요소의 처리가 끝난 뒤 상위 요소에서 추가 작업 가능
버블링을 활용하면, 개별 요소마다 리스너를 등록하지 않고 부모 요소 하나에만 이벤트를 등록해 하위 요소들을 제어할 수 있습니다.
document.getElementById('list').addEventListener('click', (event) => {
if (event.target.tagName === 'LI') {
console.log('클릭한 항목:', event.target.textContent);
}
});
e.stopPropagation() : 더 이상 상/하위로 전파 금지e.stopImmediatePropagation() : 같은 요소의 다른 리스너 실행도 중단e.preventDefault() : 브라우저 기본 동작 차단 (예: 링크 이동, 폼 제출)addEventListener(type, handler, { capture: true }) : 캡처링 단계에서 실행addEventListener(type, handler, { once: true }) : 한 번만 실행 후 자동 해제addEventListener(type, handler, { passive: true }) : 스크롤 성능 최적화 (기본 동작 차단 불가)브라우저는 클릭 좌표나 입력 지점을 기준으로 Render Tree(DOM Tree + CSSOM Tree)와 비교하여 가장 안쪽(leaf node) 요소를 찾습니다.
Render Tree에는 화면에 표시되는 요소의 박스 정보(위치, 크기, 모양 등)가 포함되어 있어, 클릭 좌표와 비교해 타겟 요소를 정확히 식별할 수 있습니다.
타겟에서 최상위 요소까지의 모든 상위 요소를 배열로 저장합니다.
저장된 경로를 따라 캡처링 → 타겟 → 버블링 순서로 이벤트가 전달됩니다.
사용자 입력(클릭, 터치, 포인터 이동 등)의 좌표에 어떤 DOM 요소가 있는지 찾는 과정입니다.
관련 프로퍼티 / 메서드
e.target → Hit Test로 찾은 가장 안쪽 요소e.currentTarget → 현재 실행 중인 리스너가 등록된 요소e.composedPath() → 전파 경로 배열 반환document.elementFromPoint(x, y) → 해당 좌표의 최상위 요소 반환document.elementsFromPoint(x, y) → 해당 좌표 아래의 모든 요소 배열 반환⭐️ target vs currentTarget
parent.addEventListener('click', (e) => { console.log('target:', e.target); // 실제 클릭한 요소 console.log('currentTarget:', e.currentTarget); // 현재 실행 중인 리스너가 등록된 요소 });
- target: 실제 클릭된 요소 (겹쳐진 요소 중 가장 안쪽 요소)
- currentTarget: 현재 실행 중인 이벤트 리스너가 등록된 요소