HTML
Primate runs HTML templates with server-side rendering and props mapped to template literal variables.
Setup
Install
npm install @primate/html
Configure
import config from "primate/config";
import html from "@primate/html";
export default config({
modules: [html()],
});
Templates
Create HTML templates in components
using template literal syntax.
<!-- components/post-index.html -->
<h1>All posts</h1>
${posts.map(post => `
<h2>
<a href="/post/${post.id}">
${post.title}
</a>
</h2>
`).join("")}
Serve the template from a route:
// routes/posts.ts
import response from "primate/response";
import route from "primate/route";
route.get(() => {
const posts = [
{ id: 1, title: "First Post" },
{ id: 2, title: "Second Post" },
];
return response.view("post-index.html", { posts });
});
Props
Props passed to response.view
are available directly in templates as
variables.
Pass props from a route:
import response from "primate/response";
import route from "primate/route";
route.get(() => {
return response.view("user.html", {
user: { name: "John", role: "Developer" },
permissions: ["read", "write"],
});
});
Access the props in the template:
<!-- components/user.html -->
<div>
<h2>${user.name}</h2>
<p>Role: ${user.role}</p>
<ul>
${permissions.map(permission => `<li>${permission}</li>`).join("")}
</ul>
</div>
Component-Scoped Assets
HTML templates support <style>
and <script>
tags that are automatically
extracted and bundled into Primate's global app.css
and app.js
files.
<!-- components/counter.html -->
<style>
.counter {
display: flex;
gap: 1rem;
align-items: center;
}
.counter button {
padding: 0.5rem 1rem;
border: 1px solid #ccc;
background: #f9f9f9;
}
</style>
<div class="counter">
<button onclick="decrement()">-</button>
<span id="count">${count}</span>
<button onclick="increment()">+</button>
</div>
<script>
function increment() {
const span = document.getElementById('count');
span.textContent = parseInt(span.textContent) + 1;
}
function decrement() {
const span = document.getElementById('count');
span.textContent = Math.max(0, parseInt(span.textContent) - 1);
}
</script>
While the CSS and JavaScript appear local to the component, they are extracted during build time and included in the global bundle.
Escaping
All props are automatically HTML-escaped for security. To output raw HTML, you'll need to handle it carefully in your template logic.
Use \${...}
to output literal ${...}
text in templates:
<!-- This renders: Learn about ${variable} syntax -->
<p>Learn about \${variable} syntax</p>
Configuration
Option | Type | Default | Description |
---|---|---|---|
fileExtensions | string[] |
[".html"] |
Associated file extensions |
Example
import html from "@primate/html";
import config from "primate/config";
export default config({
modules: [
html({
// add `.htm` to associated file extensions
fileExtensions: [".html", ".htm"],
}),
],
});