복사했더니 빈 값 — innerText는 화면에 보이는 것만 읽는다
innerText는 화면에 보이는 텍스트만 읽어 숨겨진 요소에서 빈 값을 반환하므로, 데이터 그대로를 가져오려면 textContent를 사용해야 합니다

상황
접었다 펼치는 긴 글이 있다. 화면에는 요약본이 보이고, "더보기"를 누르면 전문이 나타난다. 마크업은 흔한 형태다 — 요약본과 전문을 둘 다 DOM에 넣어두고 display로 토글한다.
<div id="full" style="display:none">…전문 5000자…</div>
<div id="summary">…앞부분 200자… <button>더보기</button></div>여기에 "본문 복사" 버튼을 붙였다. 전문을 복사해야 하니 당연히 #full을 읽는다.
const text = document.querySelector('#full').innerText;
navigator.clipboard.writeText(text);짧은 글은 잘 된다. 그런데 긴 글에서만 복사 결과가 빈 값이었다. 에러는 없다. 클립보드에 그냥 아무것도 안 들어간다.
문제
innerText와 textContent는 이름이 비슷하지만 읽는 대상이 다르다.
textContent— DOM 트리의 텍스트 노드를 그대로 잇는다. 렌더링과 무관하다.innerText— "사람이 화면에서 읽는 대로"의 텍스트를 돌려준다. 그래서 렌더 결과에 의존한다: CSS로 숨긴 요소는 건너뛰고,display:none인 요소는 빈 문자열을 반환한다.
#full은 접힌 상태에서 display:none이다. 그래서 innerText가 빈 값을 준 것이다. 화면에 안 보이니 "읽을 텍스트가 없다"고 판단한 것 — 명세대로 동작한 것이지 버그가 아니다.
짧은 글에서 됐던 건 우연이다. 짧으면 접기 자체가 안 일어나 #full이 처음부터 펼쳐져(display 정상) 있었을 뿐이다. "됐다"가 조건부였는데 그걸 몰랐다.
이 실패에는 신호가 없다. 예외도, 콘솔 경고도 없다. 클립보드에 빈 문자열이 정상적으로 쓰인다. 사용자가 다른 곳에 붙여넣기 전까지 아무도 모른다.
왜 innerText가 이렇게 동작하나
innerText는 원래 "선택해서 복사하면 나올 법한 텍스트"를 의도한 API다. 그래서 레이아웃을 반영한다 — display:none은 빼고, <br>이나 블록 요소의 줄바꿈은 \n으로 넣고, text-transform: uppercase까지 반영한다. 그 대가로 읽는 순간 레이아웃 계산(reflow)을 유발하고, 렌더 상태가 값에 새어든다.
textContent는 정반대다. DOM에 있는 글자를 그대로 준다. 숨겨져 있든 화면 밖이든 상관없다. 대신 <br>을 줄바꿈으로 바꿔주지 않는다(그냥 사라진다).
즉 **"화면에 보이는 대로"가 필요하면 innerText, "데이터에 있는 대로"가 필요하면 textContent**다. 숨긴 요소에서 값을 꺼내는 건 후자의 일이다.
해결
숨겨져 있을 수 있는 요소에서 텍스트를 읽을 때는 innerText를 쓰지 않는다.
// display 상태와 무관하게 읽힌다
const text = el.textContent;단, textContent는 <br>이나 블록 경계의 줄바꿈을 살려주지 않는다. 줄바꿈이 의미가 있는 본문이라면 노드를 직접 훑어 <br>과 블록 요소를 \n으로 바꿔야 한다.
function readText(root) {
let out = '';
root.childNodes.forEach(node => {
if (node.nodeType === Node.TEXT_NODE) out += node.textContent;
else if (node.nodeName === 'BR') out += '\n';
else if (node.nodeType === Node.ELEMENT_NODE) {
out += readText(node);
if (getComputedStyle(node).display === 'block') out += '\n';
}
});
return out;
}숨긴 요소를 잠깐 보이게 했다가 innerText로 읽고 되돌리는 방법도 이론상 되지만, reflow를 강제로 두 번 일으키고 그 사이 화면이 깜빡일 수 있어 권하지 않는다.
정리
innerText는 렌더 결과를 읽는다.display:none요소에서는 빈 문자열이다.textContent는 DOM의 글자를 읽는다. 숨김과 무관하지만 줄바꿈을 안 살린다.- 접기/펼치기처럼 요소가 숨겨질 수 있는 곳에서 값을 꺼낼 때
innerText를 쓰면, "숨겨진 항목만 조용히 빈 값"이 된다. 에러가 없어 오래 숨는다. - "짧은 입력에서는 됐다"는 통과 조건이 우연일 수 있다. 됐을 때 왜 됐는지를 확인하지 않으면, 안 되는 경우가 나중에 사용자 쪽에서 터진다.