Template Syntax (htm)
DM Note uses the htm library to convert templates to React Elements. It allows intuitive writing close to standard HTML syntax.
Basic Syntax
Value Interpolation
template: (state, settings, { html }) => html`
<div>Current value: ${state.value}</div>
<div style="color: ${settings.color};">Colored text</div>
`;Function interpolation is not supported. javascript // ❌ Wrong html` <div>${(state) => state.value}</div>` // ✅ Correct html` <div>${state.value}</div>`
Style Attribute
// ✅ Recommended: Write directly as string
html`<div style="color: ${color}; font-size: ${size}px;">Text</div>`;
// ⚠️ Works but not recommended
html`<div style=${`color: ${color};`}>Text</div>`;
// ❌ Not supported: Style object
html`<div style=${{ color: "red" }}>Text</div>`;
// Alternative: Use styleMap for style objects (React style)
html`<div style=${styleMap({ color, fontSize: `${size}px` })}>Text</div>`;Conditional Rendering
// Ternary operator
html`
<div>
${isVisible ? html`<span>Visible</span>` : html`<span>Hidden</span>`}
</div>
`;
// && operator (render only when true)
html` <div>${showGraph ? html`<div class="graph">Graph</div>` : ""}</div> `;For conditional rendering, use null, false, or empty string ("") when
there’s no content.
Array Rendering
// Return React Element array with map
html`
<div class="list">
${items.map((item) => html` <div class="item">${item.name}</div> `)}
</div>
`;
// Using index
html`
<div>
${data.map((value, index) => html` <span key=${index}>${value}</span> `)}
</div>
`;Class Names
// Specify directly as string
html`<div class="btn ${isActive ? "active" : ""}">Button</div>`;
// className works the same (React compatible)
html`<div className="btn">Button</div>`;Nested Templates
When using html tag inside another html tag, you must explicitly specify it:
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>
`;Style Definition
Inline Styles
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> Tag
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>
`;Practical Example
Stats Panel
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(
(v) => html`
<div class="stats-panel__bar" style="height: ${v}%;"></div>
`,
)}
</div>
`
: ""}
</div>
`;