DOM 요소 읽기는 화면에 있는 정보를 자바스크립트 로직으로 가져오는 단계이며,
유효성 검사, 조건 분기, 렌더링 동기화, 사용자 입력 처리의 기반이 된다.
본 글에서는 바닐라 JavaScript 환경에서 DOM 요소로부터 값을 “읽는” 대표 방법을 정리한다.
1. 텍스트 읽기: textContent, innerText, innerHTML
textContent
요소 내부의 텍스트를 그대로 가져온다. 줄바꿈과 공백을 포함하며, 화면 표시 여부와 무관하게 텍스트를 읽는다.
1
2
3
| <h1 class="title">
안녕하세요 <span style="display:none">숨김</span>
</h1>
|
1
2
| const el = document.querySelector(".title");
console.log(el?.textContent); // "안녕하세요 숨김" (숨김 여부와 무관)
|
- 장점: 빠르고 예측 가능하다.
- 권장: 텍스트가 필요하다면 기본 선택으로 삼기 좋다.
innerText
요소 내부의 텍스트를 사용자에게 보이는 형태를 기준으로 가져온다.
CSS에 의해 숨김 처리된 텍스트는 제외될 수 있고, 레이아웃 계산이 관여해 textContent보다 비용이 커질 수 있다.
1
2
3
| <h1 class="title">
안녕하세요 <span style="display:none">숨김</span>
</h1>
|
1
2
| const el = document.querySelector(".title");
console.log(el?.innerText); // "안녕하세요" (보이는 텍스트 기준)
|
화면에 보이는 텍스트 기준이 필요할 때 사용한다.
innerHTML
요소 내부의 HTML 문자열을 가져온다.
1
2
3
| <div class="content">
<strong>강조</strong> 텍스트
</div>
|
1
2
| const el = document.querySelector(".content");
console.log(el?.innerHTML); // "<strong>강조</strong> 텍스트"
|
마크업 구조 자체가 필요할 때만 제한적으로 사용한다.
읽기 자체는 문제 없으나, 이 값을 다시 조합해 DOM에 넣는 흐름에서는 XSS 위험이 생길 수 있다.
정리하자면, 대부분의 읽기 상황에서는 textContent가 가장 안전하고 일관된 선택이다.
2. 속성 읽기: getAttribute와 프로퍼티 접근
DOM 요소는 HTML 속성(attribute)과 DOM 프로퍼티(property)를 모두 가진다.
읽기 목적에 따라 적절한 방식을 선택해야 한다.
getAttribute(name)
HTML에 작성된 속성 값을 문자열로 가져온다.
1
| <img class="avatar" src="/img/cat.png" alt="고양이 아바타" />
|
1
2
3
| const img = document.querySelector(".avatar");
console.log(img?.getAttribute("alt")); // "고양이 아바타"
console.log(img?.getAttribute("src")); // "/img/cat.png"
|
반환값 : 문자열 또는 null
프로퍼티로 읽기: element.id, element.value 등
DOM 요소는 자바스크립트에서 사용하기 편한 프로퍼티를 제공한다.
1
| <input id="email" type="email" value="test@example.com" />
|
1
2
3
| const input = document.querySelector("#email");
console.log(input?.id); // "email"
console.log(input?.value); // "test@example.com" (현재 값)
|
현재 상태를 읽는 데 유리하다(특히 입력값).
data-* 읽기: dataset
기능 제어용으로 data-* 속성을 사용하는 경우가 많다.
1
2
3
4
5
6
| <ul class="todo-list">
<li class="todo-item" data-id="42" data-status="done">
<button class="btn" data-action="toggle">완료 토글</button>
<button class="btn" data-action="remove">삭제</button>
</li>
</ul>
|
1
2
3
4
5
6
7
8
| const item = document.querySelector(".todo-item");
if (!item) return;
console.log(item.dataset.id); // "42"
console.log(item.dataset.status); // "done"
const btn = item.querySelector('[data-action="toggle"]');
console.log(btn?.dataset.action); // "toggle"
|
- 반환값은 기본적으로 문자열이다.
- 숫자가 필요하면 변환이 필요하다.
1
| const idNum = Number(item?.dataset.id);
|
3. 폼 입력값 읽기: value, checked, selectedIndex
폼 요소는 “읽기”의 비중이 매우 높다. 특히 value는 가장 많이 등장한다.
input, textarea 읽기 : value
1
2
| <input id="nickname" type="text" value="test" />
<textarea id="bio">소개 글</textarea>
|
1
2
3
4
5
| const nickname = document.querySelector("#nickname");
const bio = document.querySelector("#bio");
console.log(nickname?.value); // "test"
console.log(bio?.value); // "소개 글"
|
체크박스/라디오 상태 읽기 : checked
1
2
3
4
5
6
7
8
9
10
11
| <label>
<input id="agree" type="checkbox" checked />
약관 동의
</label>
<label>
<input name="gender" type="radio" value="M" checked /> 남
</label>
<label>
<input name="gender" type="radio" value="F" /> 여
</label>
|
1
2
3
4
5
| const agree = document.querySelector("#agree");
console.log(agree?.checked); // true
const gender = document.querySelector('input[name="gender"]:checked');
console.log(gender?.value); // "M"
|
select 값 읽기
1
2
3
4
| <select id="city">
<option value="seoul">서울</option>
<option value="incheon" selected>인천</option>
</select>
|
1
2
3
4
| const sel = document.querySelector("#city");
console.log(sel?.value); // "incheon"
console.log(sel?.selectedIndex); // 1
|
4. 클래스/상태 읽기: classList, matches, closest
특정 클래스 보유 여부: classList.contains
1
| <button class="btn active">저장</button>
|
1
2
| const btn = document.querySelector(".btn");
console.log(btn?.classList.contains("active")); // true
|
선택자 일치 여부: matches
1
2
3
4
| <nav class="menu">
<a class="item" href="#">홈</a>
<a class="item" href="#">소개</a>
</nav>
|
1
2
3
4
5
6
7
8
| document.addEventListener("click", (e) => {
const t = e.target;
if (!(t instanceof Element)) return;
if (t.matches(".menu .item")) {
console.log("메뉴 아이템 클릭");
}
});
|
가장 가까운 조상 탐색: closest
1
2
3
4
5
| <div class="card" data-id="7">
<div class="content">
<button class="like">좋아요</button>
</div>
</div>
|
1
2
3
4
5
6
7
8
9
| document.addEventListener("click", (e) => {
const t = e.target;
if (!(t instanceof Element)) return;
if (!t.matches(".like")) return;
const card = t.closest(".card");
console.log(card?.dataset.id); // "7"
});
|
5. 스타일/크기 읽기: getComputedStyle, getBoundingClientRect
실제 적용된 CSS 읽기: getComputedStyle
1
2
3
4
5
| <div class="box">BOX</div>
<style>
.box { width: 120px; padding: 10px; border: 1px solid #ddd; }
</style>
|
1
2
3
4
5
6
| const el = document.querySelector(".box");
if (el) {
const style = getComputedStyle(el);
console.log(style.width); // "120px"
console.log(style.padding); // "10px"
}
|
위치/크기 읽기: getBoundingClientRect
1
2
3
4
5
| <div class="banner">BANNER</div>
<style>
.banner { margin-top: 40px; height: 60px; }
</style>
|
1
2
3
4
5
| const el = document.querySelector(".banner");
if (el) {
const rect = el.getBoundingClientRect();
console.log(rect.top, rect.left, rect.width, rect.height);
}
|
6. DOM 구조 읽기: 부모/자식/형제 탐색
1
2
3
4
5
| <ul class="list">
<li class="item">A</li>
<li class="item current">B</li>
<li class="item">C</li>
</ul>
|
1
2
3
4
5
6
| const current = document.querySelector(".item.current");
if (!current) return;
console.log(current.parentElement?.className); // "list"
console.log(current.previousElementSibling?.textContent); // "A"
console.log(current.nextElementSibling?.textContent); // "C"
|
7. 실전에서 자주 쓰는 “읽기” 패턴
존재 여부를 먼저 확인한다
1
| <h2 class="toast" hidden>저장되었습니다.</h2>
|
1
2
3
4
| const toast = document.querySelector(".toast");
if (!toast) return;
console.log(toast.hasAttribute("hidden")); // true
|
문자열을 전제로 두고 타입 변환을 명시한다.
1
| <p id="price">12000</p>
|
1
2
3
4
| const priceText = document.querySelector("#price")?.textContent ?? "0";
const price = Number(priceText);
console.log(price + 1000); // 13000
|
마무리
DOM 요소 읽기는
- 텍스트(textContent)
- 속성(getAttribute/dataset)
- 입력값(value/checked)
- 상태(classList)
- 스타일(getComputedStyle)
무엇을 읽는지에 따라 API가 달라지며,
예시 HTML 구조를 함께 두고 null과 문자열 타입을 기본 전제로 안전하게 처리하는 것이 중요하다.