Template Element

내장 <template> 요소는 HTML 마크업 템플릿에 대한 저장요소로 취급된다. 브라우저는 이를 무시하고, 오로지 문법 상 온전한지만을 체크하는데, 우리가 우너한다면, 이를 이용해서 다른 요소들을 만들어낼 수도 있다.

사실, 우리는 이미 이론 상 보이지 않는 요소들을 어디서든 만들어 낼 수 있다. 대체 이 <template>가 특별한 점은 무엇일까?

먼저, 이들의 내용(content)는 문법상 올바른 HTML이면 무엇이든 가능하다. 다시 말해, 적절히 태그만 열고닫았으면 문제가 없다.

무슨 소리냐고? 단순히 우리가 <tr><td>만을 이용해서 테이블을 만들면, 브라우저는 부적절한 DOM 구조를 감지하고, 알아서 <table>을 추가해 DOM 구조를 수정해준다. 반면 <template>의 경우는 우리가 작성한 내용 그대로를 유지시켜준다.

<template> <tr> <td>Contents</td> </tr> </template>

마찬가지로, <template>에는 스타일과 스크립트 태그가 포함될 수 있다.

<template> <style> p { font-weight: bold; } </style> <script> alert("Hello"); </script> </template>

브라우저는 <template>의 내용들을 문서와 상관없는 것으로 간주한다. 때문에 스타일은 적용되지 않고, 스크립트 역시 마찬가지다.

템플릿 삽입하기

템플릿의 내용은 content 프로퍼티를 통해 이용할 수 있는데, 이는 DocumentFragment라는 특수한 DOM 노드 타입이다.

이는 다른 DOM 노드들과 거의 동일하게 다룰 수 있으나, 유일한 차이점은, 어딘가에 삽입되는 경우, 노드 본인이 아닌 자식들이 대신 삽입된다는 점이다.

<template id="tmpl"> <script> alert("Hello"); </script> <div class="message">Hello, world!</div> </template> <script> let elem = document.createElement('div'); // 재사용을 위해 템플릿 컨텐츠를 복사하여 사용한다. elem.append(tmpl.content.cloneNode(true)); document.body.append(elem); // append에 의해 body에 요소가 추가되고 나서야 위의 script가 동작한다. </script>

Shadow DOM과 함께 사용해보자.

<template id="tmpl"> <style> p { font-weight: bold; } </style> <p id="message"></p> </template> <div id="elem">Click me</div> <script> elem.onclick = function() { elem.attachShadow({mode: 'open'}); elem.shadowRoot.append(tmpl.content.cloneNode(true)); // (*) elem.shadowRoot.getElementById('message').innerHTML = "Hello from the shadows!"; }; </script>