r-for Directive
Render reactive collections with stable keys that preserve each item’s identity.
r-for renders repeated template instances from arrays, iterables, and object-like values.
Render reactive collections with stable keys that preserve each item’s identity.
Try it live
- Design the interfacekey: design
- Connect the statekey: build
- Verify the behaviorkey: check
Reverse the order: stable keys let Regor reuse the existing row elements.
import { html, sref } from 'regor'
const initial = [
{ id: 'design', label: 'Design the interface' },
{ id: 'build', label: 'Connect the state' },
{ id: 'check', label: 'Verify the behavior' },
]
export function createFor(interactive = false) {
const rows = sref(initial.map((row) => ({ ...row })))
return {
interactive,
rows,
reverse: () => rows([...rows()].reverse()),
remove: (id: string) => rows(rows().filter((row) => row.id !== id)),
reset: () => rows(initial.map((row) => ({ ...row }))),
}
}
export const forTemplate = html` <div class="guide-demo">
<div class="guide-session-bar">
<button type="button" @click="reverse" :disabled="!interactive">
Reverse order</button
><button type="button" @click="reset" :disabled="!interactive">
Reset list
</button>
</div>
<ul class="guide-service-list">
<li r-for="row in rows" :key="row.id">
<div>
<strong>{{ row.label }}</strong><small>key: {{ row.id }}</small>
</div>
<button
type="button"
:aria-label="'Remove ' + row.label"
@click="remove(row.id)"
:disabled="!interactive"
>
Remove
</button>
</li>
</ul>
<p r-if="rows.length === 0" class="guide-empty">
The list is empty. Reset it to start again.
</p>
<p class="guide-hint">
Reverse the order: stable keys let Regor reuse the existing row elements.
</p>
</div>` import { createApp, useScope } from 'regor'
import { directiveExamples } from './examples'
const element = document.getElementById('directive-demo')
const name = element?.dataset.example
if (element && name && Object.hasOwn(directiveExamples, name)) {
const example = directiveExamples[name as keyof typeof directiveExamples]
createApp<object>(
useScope<object>(() => example.create(true)),
{ element, template: example.template },
)
} Reverse the list or remove rows. Keys let surviving items keep their DOM elements.
Usage
<li r-for="item in items">{{ item }}</li> You can use in or of:
<li r-for="item of items">{{ item }}</li> Index Variable
Use #-prefixed variable for index:
<li r-for="(item, #i) in items">{{ i }} - {{ item }}</li> Iterating Over Objects
Object iteration is supported:
<li r-for="(key, value) in person">{{ key }}: {{ value }}</li> Object Destructuring
Destructuring is supported:
<li r-for="{ name, age }, #i in users">{{ i }} - {{ name }} ({{ age }})</li> Complex Expressions
Any valid expression can provide iterable data:
<ul>
<li r-for="n in numbers.filter((n) => n > 5)">{{ n }}</li>
</ul> Keying (key and :key)
For stable identity and predictable updates, set a key on repeated nodes.
<li r-for="row in rows" :key="row.id" r-text="row.name"></li> Important behavior in Regor templates:
key="row.id"and:key="row.id"are both expression-based for list keying.- Nested key paths are supported, including
a.b.c.d. - Use stable, unique keys from your domain model.
If keys are unstable, DOM reuse quality degrades and updates become less predictable.
Table Templates
r-for supports native table structures and component-based captions, sections, rows, cells, column groups, and columns.
<table>
<tbody>
<TableRow r-for="row in rows" :row="row" />
</tbody>
</table> const tableCell = defineComponent(html`<td><span>{{ value }}</span></td>`, {
props: ['value'],
})
const tableRow = defineComponent(
html`<tr>
<TableCell :value="row.name" />
<TableCell :value="row.age" />
</tr>`,
{ props: ['row'] },
) <table>
<colgroup r-for="group in columnGroups">
<col r-for="col in group.cols" :data-width="col.width" />
</colgroup>
</table> Best Practices
- Keep row templates minimal.
- Use stable keying.
- Avoid expensive per-row expressions in large lists.
- Prefer pagination/windowing for very large data sets.
Use row.id when it is stable and unique. The row position changes when you reorder a list.