List Rendering
Render lists of data using the <template pp-for> directive.
Basic Iteration
Use the item in items syntax to loop through arrays. The content inside the template is repeated for each entry.
shopping-list.html
<ul class="list-disc pl-6">
<template pp-for="fruit in fruits">
<li>{fruit}</li>
</template>
</ul>
<script type="text/pp">
const [fruits, setFruits] = pp.state([
"Apples",
"Bananas",
"Cherries"
]);
</script>
Accessing Index
Need the position of the item? Use the parenthesis syntax: (item, index) in items.
leaderboard.html
<div class="space-y-2">
<template pp-for="(player, i) in leaderboard">
<div class="flex justify-between border-b py-2">
<span>Rank #{i + 1}</span>
<strong>{player}</strong>
</div>
</template>
</div>
<script type="text/pp">
const [leaderboard, setBoard] = pp.state(["Alice", "Bob", "Charlie"]);
</script>
Rendering Objects & Keys
When rendering objects, access properties using dot notation.
Important: Always add a unique
key="{id}" attribute to the root element inside the loop. This ensures the framework can efficiently update, reorder, or remove items without bugs.
user-grid.html
<div class="grid grid-cols-3 gap-4">
<template pp-for="user in users">
<!-- Unique Key is mandatory for dynamic lists -->
<div key="{user.id}" class="border p-4 rounded-lg shadow-sm">
<h4 class="font-bold">{user.name}</h4>
<p class="text-sm text-gray-500">{user.role}</p>
<button
class="mt-2 text-red-500 text-xs hover:underline"
onclick="removeUser(user.id)"
>
Remove User
</button>
</div>
</template>
</div>
<script type="text/pp">
const [users, setUsers] = pp.state([
{ id: 101, name: "Sarah", role: "Designer" },
{ id: 102, name: "Mike", role: "Developer" },
{ id: 103, name: "Jessica", role: "Manager" }
]);
function removeUser(id) {
setUsers(users.filter(u => u.id !== id));
}
</script>
Rendering Dynamic Icons
Just like React, you can store SVG strings or icons in your state and render them dynamically as HTML tags. PulsePoint treats dot-notation tags (e.g., <item.icon />) as dynamic components.
nav-menu.html
<ul class="flex gap-4">
<template pp-for="link in links">
<li key="{link.id}" class="flex items-center gap-2">
<!-- The icon is rendered dynamically from the state string -->
<link.icon class="size-4 text-muted-foreground" />
<span>{link.label}</span>
</li>
</template>
</ul>
<script type="text/pp">
// Define your icon as a standard SVG string
const homeIcon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>`;
const settingsIcon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>`;
const [links, setLinks] = pp.state([
{ id: 1, label: "Home", icon: homeIcon },
{ id: 2, label: "Settings", icon: settingsIcon },
]);
</script>