<body>
<p>안녕하세요. 오늘도 좋은 날씨네요!</p>
<my-modal>
<!-- 여기에 모달의 내용을 넣고 싶다 -->
</my-modal>
</body>
my-modal
이라는 Custom Element를 만들었습니다. 모달의 모양만 가지고 있는 엘리먼트인데, 그럼 모달안의 내용은 어떻게 전달할까요?
Light DOM
<body>
<p>안녕하세요. 오늘도 좋은 날씨네요!</p>
<my-modal>
<h1>오늘 날씨는 15도입니다.</h1>
<p>기온이 많이 올라갔지만 따뜻하게 입는 것 잊지 마세요!</p>
</my-modal>
</body>
customElements.define('my-modal', class MyModal extends HTMLElement {
constructor() {
super();
this.childrenHTML = this.innerHTML;
this.innerHTML = `
<style>
dialog::backdrop {
background: rgba(0, 0, 0, 0.3);
}
</style>
<dialog>
<form method="dialog">
${this.childrenHTML}
<button>확인</button>
</form>
</dialog>
`;
}
connectedCallback() {
this.querySelector('dialog').showModal();
}
});
Shadow DOM을 사용하지 않을 시, <my-modal>
내의 HTML은 innerHTML
로 접근할 수 있습니다.
임시로 this.childrenHTML
에 저장한 후 위와 같이 템플릿에 삽입할 수 있습니다.
(childrenHTML
은 임의로 정한 이름이기 때문에, 다른 걸로 바꾸어 사용해도 무관합니다)
Shadow DOM
만일 Shadow DOM을 사용한다면 위의 방법대로 할 수 있을까요?
Shadow DOM의 경우, slot element를 사용하면 됩니다.
<body>
<p>안녕하세요. 오늘도 좋은 날씨네요!</p>
<my-modal>
<h1>오늘 날씨는 15도입니다.</h1>
<p>기온이 많이 올라갔지만 따뜻하게 입는 것 잊지 마세요!</p>
</my-modal>
</body>
customElements.define('my-modal', class MyModal extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
<style>
dialog::backdrop {
background: rgba(0, 0, 0, 0.3);
}
</style>
<dialog>
<form method="dialog">
<slot></slot> <!-- host의 내용을 여기에 표시 -->
<button>확인</button>
</form>
</dialog>
`;
}
connectedCallback() {
this.shadowRoot.querySelector('dialog').showModal();
}
});
<my-modal>
내의 html 내용은 <slot></slot>
에 표시됩니다.
slot에 이름 지정
slot
에는 이름을 지정할 수도 있습니다.
<my-modal>
<h1 slot="title">오늘 날씨는 15도입니다.</h1>
<p slot="content">기온이 많이 올라갔지만 따뜻하게 입는 것 잊지 마세요!</p>
</my-modal>
customElements.define('my-modal', class MyModal extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
<style>
dialog::backdrop {
background: rgba(0, 0, 0, 0.3);
}
</style>
<dialog>
<form method="dialog">
<slot name="title"></slot>
<hr >
<slot name="content"></slot>
<button>확인</button>
</form>
</dialog>
`;
}
connectedCallback() {
this.shadowRoot.querySelector('dialog').showModal();
}
});
이름을 지정하면, slot
을 여러 개 만들어 어떠한 위치에 삽입을 할 것인지도 결정할 수 있습니다.
::slotted()
::slotted()
pseudo selector를 사용하면, slot
내의 엘리먼트에 대해 스타일을 지정할 수 있습니다.
<my-modal important>
<h1 slot="title">오늘 날씨는 15도입니다.</h1>
<p slot="content">기온이 많이 올라갔지만 따뜻하게 입는 것 잊지 마세요!</p>
</my-modal>
customElements.define('my-modal', class MyModal extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
<style>
dialog::backdrop {
background: rgba(0, 0, 0, 0.3);
}
:host([important]) ::slotted(h1) {
text-decoration: underline;
color: blue;
}
</style>
<dialog>
<form method="dialog">
<slot name="title"></slot>
<hr >
<slot name="content"></slot>
<button>확인</button>
</form>
</dialog>
`;
}
connectedCallback() {
this.shadowRoot.querySelector('dialog').showModal();
}
});
맺음말
slot 기능을 사용하면 외부에서 <my-button>
, <my-alert>
등의 엘리먼트들을 조합하여 사용할 수 있습니다. 따라서 컴포넌트를 재사용하는 데에 큰 도움이 되니 잘 사용하면 좋을 것 같습니다.