Skip to Content
Documentation템플릿 문법

템플릿 문법 (htm)

DM Note는 htm 라이브러리를 사용하여 템플릿을 React Element로 변환합니다. 표준 HTML 문법에 가까운 직관적인 작성이 가능합니다.

기본 문법

값 보간

template: (state, settings, { html }) => html` <div>현재 값: ${state.value}</div> <div style="color: ${settings.color};">색상 텍스트</div> `;

함수 보간은 지원되지 않습니다. javascript // ❌ 잘못된 방법 html` <div>${(state) => state.value}</div>` // ✅ 올바른 방법 html` <div>${state.value}</div>`

스타일 속성

// ✅ 권장: 문자열로 직접 작성 html`<div style="color: ${color}; font-size: ${size}px;">텍스트</div>`; // ⚠️ 동작하지만 권장하지 않음 html`<div style=${`color: ${color};`}>텍스트</div>`; // ❌ 지원 안 됨: 스타일 객체 html`<div style=${{ color: "red" }}>텍스트</div>`; // 대안: styleMap으로 스타일 객체 전달 (React 스타일) html`<div style=${styleMap({ color, fontSize: `${size}px` })}>텍스트</div>`;

조건부 렌더링

// 삼항 연산자 html` <div>${isVisible ? html`<span>보임</span>` : html`<span>숨김</span>`}</div> `; // && 연산자 (true일 때만 렌더링) html` <div>${showGraph ? html`<div class="graph">그래프</div>` : ""}</div> `;

조건부 렌더링에서 내용이 없을 때는 null, false, 또는 빈 문자열("")을 사용할 수 있습니다.

배열 렌더링

// map으로 React Element 배열 반환 html` <div class="list"> ${items.map((item) => html` <div class="item">${item.name}</div> `)} </div> `; // 인덱스 활용 html` <div> ${data.map((value, index) => html` <span key=${index}>${value}</span> `)} </div> `;

클래스 이름

// 문자열로 직접 지정 html`<div class="btn ${isActive ? "active" : ""}">버튼</div>`; // className도 동일하게 동작 (React 호환) html`<div className="btn">버튼</div>`;

중첩 템플릿

html 태그 안에서 다시 html 태그를 사용할 때는 꼭 명시해야 합니다:

html` <div class="container"> ${items.map( (item) => html` <div class="card"> ${item.highlighted ? html`<strong>${item.name}</strong>` : html`<span>${item.name}</span>`} </div> ` )} </div> `;

스타일 정의

인라인 스타일

template: (state, settings, { html }) => html` <div style=" background: rgba(0, 0, 0, 0.8); color: ${settings.textColor}; padding: 16px; border-radius: 8px; " > ${state.value} </div> `;

<style> 태그

template: (state, settings, { html }) => html` <style> .panel { background: rgba(0, 0, 0, 0.8); padding: 16px; border-radius: 8px; } .panel__value { font-size: 24px; font-weight: bold; color: ${settings.textColor}; } .panel__label { font-size: 12px; opacity: 0.7; } </style> <div class="panel"> <div class="panel__value">${state.value}</div> <div class="panel__label">KPS</div> </div> `;

실전 예제

통계 패널

template: (state, settings, { html }) => html` <style> .stats-panel { background: ${settings.bgColor}; padding: 16px; border-radius: 12px; color: white; font-family: system-ui, sans-serif; } .stats-panel__header { font-size: 12px; text-transform: uppercase; letter-spacing: 0.1em; opacity: 0.7; } .stats-panel__value { font-size: 48px; font-weight: bold; line-height: 1; margin: 8px 0; } .stats-panel__graph { display: flex; gap: 2px; height: 40px; align-items: flex-end; } .stats-panel__bar { flex: 1; background: ${settings.barColor}; border-radius: 2px 2px 0 0; transition: height 0.1s ease; } </style> <div class="stats-panel"> <div class="stats-panel__header">Live KPS</div> <div class="stats-panel__value">${state.kps?.toFixed(1) ?? "0.0"}</div> ${settings.showGraph ? html` <div class="stats-panel__graph"> ${(state.history ?? []).map((value) => { const max = state.max || 1; const height = Math.round((value / max) * 100); return html` <div class="stats-panel__bar" style="height: ${height}%; opacity: ${height > 80 ? 1 : 0.5};" ></div> `; })} </div> ` : ""} </div> `;

다국어 패널

template: (state, settings, { html, t, locale }) => html` <div class="panel" data-locale="${locale}"> <h3>${t("title")}</h3> <p>${t("description")}</p> <div class="value">${t("count")}: ${state.count}</div> </div> `;

주의사항

항목설명
함수 보간 미지원${(s) => s.value} 형태는 React child로 렌더링할 수 없어 오류
중첩 템플릿내부에서 다시 html 태그를 명시해야 함
빈 값 처리조건부 렌더링에서 null/false/"" 사용 가능
스타일 객체 미지원styleMap({ ... }) 또는 React 스타일 객체 사용 가능
이벤트 핸들러템플릿 내부에서 직접 함수 바인딩 불가
문자열 템플릿 이벤트HTML 문자열(레거시)에서는 data-plugin-handler 패턴 사용

이벤트 핸들러

템플릿이 문자열(레거시 HTML) 을 반환하는 경우에는 이벤트 핸들러를 직접 바인딩할 수 없습니다. 이때는 data-plugin-handler 속성을 사용합니다:

// 핸들러 등록 window.myHandler = () => { console.log("클릭됨!"); }; // 템플릿에서 사용 html`<button data-plugin-handler="myHandler">클릭</button>`; // 클린업 시 제거 dmn.plugin.registerCleanup(() => { delete window.myHandler; });

Display Element의 루트 레벨 이벤트는 config에서 직접 등록할 수 있습니다:

dmn.ui.displayElement.add({ template: (state, { html }) => html`<div>클릭하세요</div>`, onClick: async () => { console.log("패널 클릭됨!"); }, });