Day 13Web Components 만들기

지금 이 페이지 맨 위에 있는 <berry-nav></berry-nav> 태그, 그게 바로 오늘 배울 것이다. 직접 만든 HTML 태그를 브라우저가 진짜 요소처럼 인식하게 만드는 표준 기능이다. 실제 정의를 ~/Documents/_system/components.js에서 지금 열어봐도 좋다.

1. customElements.define

class TempBadge extends HTMLElement {
  connectedCallback() {              // 요소가 실제 DOM에 삽입될 때 호출됨
    this.render();
  }

  render() {
    const c = Number(this.getAttribute("celsius"));
    const color = c >= 80 ? "#f97583" : c >= 65 ? "#e2c08d" : "#4ec9b0";
    this.style.color = color;
    this.textContent = `${c}°C`;
  }
}

customElements.define("temp-badge", TempBadge);
// 이제 HTML 어디서든: 

2. attributeChangedCallback — 속성이 바뀔 때 반응

class TempBadge extends HTMLElement {
  static get observedAttributes() {    // 이 목록에 있는 속성만 감시됨
    return ["celsius"];
  }

  attributeChangedCallback(name, oldValue, newValue) {
    this.render();                       // 값이 바뀔 때마다 다시 그림
  }

  connectedCallback() {
    this.render();
  }

  render() { /* ... */ }
}
berry-nav도 이 두 콜백(connectedCallback 등) 패턴을 그대로 쓴다. 지금 배우는 게 장난감 예제가 아니라 이 사이트가 실제로 돌아가는 방식 그 자체다.

3. Shadow DOM (선택)

내부 스타일/구조를 바깥 페이지와 완전히 격리하고 싶을 때 쓴다. 오늘 과제에선 필수 아님 — 알아만 두면 된다.

class Isolated extends HTMLElement {
  connectedCallback() {
    const shadow = this.attachShadow({ mode: "open" });
    shadow.innerHTML = `

바깥 CSS 영향 안 받음

`; } }

🎯 실습 과제 — _submissions/day13.js

과제 1. temp-badge 컴포넌트
위 예제를 직접 완성해서 <temp-badge celsius="67"></temp-badge>"67°C" 텍스트를, 80 이상이면 빨강 계열, 65 이상이면 노랑 계열, 미만이면 초록 계열 글자색으로 렌더링하도록 만든다.

과제 2. 속성 변경에 반응
observedAttributesattributeChangedCallback을 구현해서, JS로 el.setAttribute("celsius", "90")을 호출하면 색과 텍스트가 자동으로 갱신되게 만든다.

과제 3. 라벨 표시
celsius 외에 label이라는 선택적 속성을 추가한다. 있으면 "[label] 67°C" 형식으로, 없으면 그냥 "67°C"로 렌더링한다.

과제 4 (도전). 커스텀 이벤트 발생
온도가 80 이상으로 바뀌는 순간 this.dispatchEvent(new CustomEvent("danger", { detail: { celsius: c } }))로 커스텀 이벤트를 발생시킨다 (바깥에서 el.addEventListener("danger", ...)로 들을 수 있게).

✅ 다 작성했으면:
cd ~/Documents/javascript-2주완성
bun _grade.ts day13