이번 편의 결과물: (실습 없음) 메모 카드를 Custom Element로 바꾼다면 무엇이 달라지는지 개념만 정리하고, 이 구조를 깊게 다루는 다음 과목으로 연결합니다. · 다루는 개념: Custom Elements, Shadow DOM 한 문단 소개
이 편에서 다루는 범위
이 편은 코드를 작성하지 않습니다. 지금까지 notes-app은 document.createElement와 innerHTML로 DOM을 직접 조립하는 방식으로 만들었습니다. 이 방식과 Web Components(Custom Elements, Shadow DOM)라는 대안이 무엇이 다른지, 왜 별도 과목(web_component)에서 다루는지만 정리합니다.
개념 정리
지금까지 만든 방식과 Custom Element의 차이
19편까지 createNoteItem(note) 함수는 <article>을 만들고 자식 요소를 하나씩 append했습니다. 이 함수를 호출하는 쪽(render.js)이 내부 구조를 전부 알아야 합니다. Custom Element는 이 조립 로직을 <note-item>이라는 새 HTML 태그 안에 캡슐화합니다.
| 비교 항목 | 지금 방식(함수로 DOM 조립) | Custom Element |
|---|---|---|
| 사용법 | createNoteItem(note) 호출 후 append | <note-item> 태그를 HTML에 직접 씀 |
| 내부 구조 은닉 | 없음(호출부가 구조를 알아야 함) | Shadow DOM으로 내부 마크업·스타일 은닉 가능 |
| 상태 변경 반응 | 다시 그려서 replaceChildren | 표준 라이프사이클 콜백(attributeChangedCallback)으로 반응 |
| 스타일 충돌 | 전역 CSS 클래스 이름 관리 필요(.note-item) | Shadow DOM 안 스타일은 바깥에 새지 않음 |
Custom Elements 한 문단
customElements.define('note-item', class extends HTMLElement { ... })으로 새 태그를 등록합니다. connectedCallback은 요소가 문서에 삽입될 때, attributeChangedCallback은 지정한 속성이 바뀔 때 호출됩니다. 이 콜백 안에서 지금 render.js가 하던 DOM 조립을 수행할 수 있습니다.
Shadow DOM 한 문단
element.attachShadow({ mode: 'open' })으로 만드는 Shadow DOM은 그 요소 안에만 적용되는 독립된 DOM 트리입니다. 안에 <style>을 넣어도 바깥 페이지의 CSS와 서로 영향을 주지 않습니다. notes-app처럼 전역 클래스 이름(.note-item, .toolbar)으로 스타일 충돌을 조심해야 했던 문제가 구조적으로 사라집니다.
notes-app을 컴포넌트화한다면
createNoteItem은class NoteItem extends HTMLElement로 옮겨가고,render.js는<note-item>태그를 만들어note데이터를 속성이나 프로퍼티로 전달하는 역할만 남습니다.- 17~19편에서 만든 첨부 미리보기·복사·공유·삭제 버튼은
NoteItem의 Shadow DOM 안에서 조립되고,main.js의 이벤트 위임은note-item이 발생시키는 커스텀 이벤트(CustomEvent)를 듣는 형태로 바뀝니다. styles.css에 있던.note-item관련 규칙은NoteItem의 Shadow DOM 내부<style>로 옮겨가, 페이지 전역 스타일과 완전히 분리됩니다.
이 전환을 실제로 해보는 것은 이 과목의 범위가 아닙니다. Custom Elements의 라이프사이클, Shadow DOM의 스타일 격리 규칙, 슬롯(slot)을 이용한 콘텐츠 합성, 폼 연동 Custom Element(ElementInternals) 등은 /javascript/web_component 과목에서 깊게 다룹니다.
왜 지금 다루지 않는가
Web Components는 이 과목이 다룬 DOM·이벤트·저장소·워커 API와 성격이 다릅니다. 지금까지의 API는 “브라우저가 이미 제공하는 기능을 가져다 쓰는” 방식이었지만, Custom Elements·Shadow DOM은 “브라우저에 새 HTML 태그를 등록하는” 확장 메커니즘입니다. 라이프사이클 콜백, 속성-프로퍼티 동기화, 슬롯 기반 콘텐츠 합성처럼 그 자체로 한 과목 분량의 개념이 있어, 이 과목에 욱여넣으면 06 규격이 정한 “결과물이 곧 목차” 원칙(편당 8~14KB, 실습 중심)을 지키기 어렵습니다. 그래서 web_component 과목이 별도로 존재합니다.
다음 과목에서 이어받을 상태
web_component 과목은 이번 notes-app의 코드를 그대로 가져가지 않고 새 실습 프로젝트에서 시작합니다. 다만 개념적으로는 지금 표에서 정리한 “함수로 만든 note-item을 <note-item> 태그로 바꾼다면”이라는 질문을 그대로 이어받아, 실제로 그 태그를 등록하고 동작시키는 과정을 다룹니다.
지금까지 만든 것
| 편 | 추가된 기능 |
|---|---|
| 04–07 | DOM 렌더링, 이벤트 위임 CRUD, 폼 검증, localStorage 저장 |
| 08–10 | fetch 동기화, AbortController 취소, URL/History 라우팅 |
| 11–14 | IndexedDB 전환, IntersectionObserver 무한 스크롤, MutationObserver·ResizeObserver, 타이머·rAF·Page Lifecycle |
| 15–16 | Web Worker 검색, Service Worker와 Cache로 오프라인 사용 |
| 17–19 | File/Blob 첨부·내보내기, Clipboard·Notification·Web Share, CSP·origin·권한 |
notes-app은 이 표의 모든 기능이 동작하는 완성된 오프라인 지원 SPA 상태로 끝납니다.
자주 하는 오해
| 오해 | 사실 |
|---|---|
| Web Components는 React 같은 프레임워크의 대체품이다 | 브라우저 표준 API이며, React·Vue 컴포넌트와 함께 쓰이기도 한다 |
| Shadow DOM을 쓰면 무조건 성능이 좋아진다 | 스타일 격리와 캡슐화가 목적이며, 성능 이점은 상황에 따라 다르다 |
| Custom Element는 클래스형 컴포넌트를 대체하는 새 문법일 뿐이다 | 라이프사이클 콜백과 속성 관찰(observedAttributes) 등 별도 개념 체계를 갖는다 |