
프론트엔드
Web Components Advanced웹 컴포넌트 심화
웹 컴포넌트(Web Components)는 Custom Elements, Shadow DOM, HTML Templates를 조합해 프레임워크 독립적인 재사용 컴포넌트를 만드는 표준 기술이다.
Custom Elements
javascript
// 커스텀 엘리먼트 정의
class MyCard extends HTMLElement {
// 관찰할 속성 목록
static observedAttributes = ['title', 'variant'];
constructor() {
super();
// Shadow DOM 생성 (open: JS로 접근 가능)
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
// DOM에 추가될 때
this.render();
}
disconnectedCallback() {
// DOM에서 제거될 때 정리
this.cleanup();
}
attributeChangedCallback(name, oldVal, newVal) {
// 속성 변경 시
this.render();
}
render() {
this.shadowRoot.innerHTML = `
<style>
:host { display: block; }
:host([variant="primary"]) .card { border-color: blue; }
.card {
padding: 1rem;
border: 1px solid #ccc;
border-radius: 8px;
}
</style>
<div class="card">
<h2>${this.getAttribute('title') || 'Card'}</h2>
<slot></slot> <!-- 콘텐츠 투영 -->
<slot name="footer"></slot> <!-- 이름 있는 슬롯 -->
</div>
`;
}
}
// 등록
customElements.define('my-card', MyCard);Shadow DOM 스타일 제어
css
/* 외부에서 Shadow DOM 스타일 영향 */
my-card {
display: block; /* 커스텀 프로퍼티는 Shadow DOM 통과 */
--card-bg: #f5f5f5;
--card-color: #333;
}
/* Shadow DOM 내부 */
:host {
/* :host = 커스텀 엘리먼트 자체 */
display: block;
}
.card {
background: var(--card-bg, white); /* CSS 변수 수신 */
color: var(--card-color, black);
}
/* 슬롯 콘텐츠 스타일 (외부 DOM) */
::slotted(p) {
margin: 0;
}Lit 라이브러리 (웹 컴포넌트 간소화)
typescript
import { LitElement, html, css } from 'lit';
import { customElement, property } from 'lit/decorators.js';
@customElement('my-button')
export class MyButton extends LitElement {
static styles = css`
button {
padding: 0.5rem 1rem;
background: var(--btn-bg, blue);
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
`;
@property({ type: Boolean }) disabled = false;
@property() label = 'Click me';
render() {
return html`
<button ?disabled=${this.disabled}
@click=${this._handleClick}>
${this.label}
</button>
`;
}
private _handleClick() {
this.dispatchEvent(new CustomEvent('my-click', { bubbles: true }));
}
}