JavaScript / createElement()와 appendChild()로 요소 추가하기
문서 객체 모델(DOM)에서 요소를 추가하려면 document.createElement()로 요소 노드를 만들고, 필요하면 document.createTextNode()로 텍스트 노드를 만든 뒤, appendChild()로 부모에 연결합니다. 노드를 만들기만 해서는 페이지에 보이지 않습니다. 실제 문서의 부모 요소에 붙여야 화면에 나타납니다.
요소 생성, 텍스트 생성, 문서에 연결하기
createElement("li")는 빈 목록 항목을 만듭니다. createTextNode("새 항목")는 태그로 해석되지 않는 텍스트 노드를 만듭니다. appendChild()는 자식 노드를 부모의 마지막 자식으로 붙입니다. 세 메서드는 기능이 서로 달라 순서를 지켜야 합니다.
const list = document.querySelector('#list');
const item = document.createElement('li');
const text = document.createTextNode('새 항목');
item.appendChild(text);
list.appendChild(item);
목록에 붙이는 마지막 줄 전까지 item은 메모리에만 있습니다. list가 null이라면 HTML에 id="list"가 있는지, 스크립트가 요소 생성 후에 실행되는지 확인하세요. MDN의 createElement() 문서와 MDN의 createTextNode() 문서에서 반환되는 노드의 종류를 볼 수 있습니다.
appendChild()는 기존 노드를 복사하지 않고 옮깁니다
이미 문서에 붙어 있는 노드를 다른 부모나 같은 부모 끝에 다시 appendChild()하면 그 노드가 이동합니다. 같은 노드가 두 개 생기지 않습니다. 여러 곳에 같은 구조가 필요하다면 새 요소를 만들거나 cloneNode()로 복제해야 합니다.
const list = document.querySelector('#list');
const first = list.firstElementChild;
if (first) {
list.appendChild(first); // 첫 항목을 마지막으로 이동
}
appendChild()는 붙인 노드를 반환합니다. 문자열을 직접 인수로 넣는 함수는 아니므로 텍스트는 createTextNode()로 만든 뒤 붙이거나, 요소의 textContent를 설정하세요. 원본 노드 이동과 반환 규칙은 MDN의 appendChild() 문서에 설명되어 있습니다.
전체 예제: 목록 항목 추가·이동·복원
아래 코드를 UTF-8로 dom-add-item.html에 저장해 브라우저에서 엽니다. 항목을 입력하고 ‘항목 추가’를 누르면 목록 맨 뒤에 들어갑니다. ‘첫 항목 뒤로 이동’은 기존 첫 노드를 마지막으로 옮깁니다. ‘처음으로’는 두 항목의 초기 목록을 다시 만듭니다.
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>목록 요소 추가·이동 실습</title>
</head>
<body>
<label for="item">추가할 항목</label>
<input id="item" type="text" value="">
<button id="add" type="button">항목 추가</button>
<button id="move" type="button">첫 항목 뒤로 이동</button>
<button id="reset" type="button">처음으로</button>
<ul id="list"></ul>
<p id="status" aria-live="polite"></p>
<script>
const list = document.querySelector('#list');
const input = document.querySelector('#item');
const status = document.querySelector('#status');
function addItem(label) {
const item = document.createElement('li');
const text = document.createTextNode(label);
item.appendChild(text);
list.appendChild(item);
}
function reset() {
list.replaceChildren();
addItem('첫 항목');
addItem('둘째 항목');
input.value = '';
status.textContent = '처음 목록으로 돌아왔습니다.';
}
document.querySelector('#add').addEventListener('click', () => {
const label = input.value.trim();
if (label === '') {
status.textContent = '추가할 내용을 입력하세요.';
return;
}
addItem(label);
status.textContent = `${label} 항목을 추가했습니다.`;
input.value = '';
});
document.querySelector('#move').addEventListener('click', () => {
list.appendChild(list.firstElementChild);
status.textContent = '첫 항목을 맨 뒤로 옮겼습니다.';
});
document.querySelector('#reset').addEventListener('click', reset);
reset();
</script>
</body>
</html>
처음에는 ‘첫 항목’, ‘둘째 항목’ 순서입니다. 셋째 항목을 추가하면 세 항목이 되고, 이동 버튼을 누르면 ‘첫 항목’이 마지막으로 갑니다. 빈 입력은 추가하지 않고 안내를 표시합니다. 재설정은 직접 이 예제에서 만든 목록 내용을 다시 구성하며, 입력란도 비웁니다.
사용자 입력과 단순한 대체 방법
텍스트를 만들기 위해 innerHTML에 사용자 입력을 이어 붙이지 마세요. 태그로 해석되거나 스크립트 실행 경로가 될 수 있습니다. 이 예제는 createTextNode()를 사용해 입력 문구를 문자 그대로 표시합니다. 태그를 만들 때는 createElement()에 고정된 허용 태그 이름을 전달하는 편이 안전합니다.
텍스트 노드를 별도 변수로 다룰 필요가 없는 간단한 경우에는 item.textContent = label도 가능합니다. 여러 문자열이나 노드를 한 번에 넣어야 한다면 Element.append()도 선택지입니다. 다만 append()는 반환값이 없고 appendChild()는 붙인 노드를 반환하므로 이후 코드가 무엇을 필요로 하는지 확인하세요.




