@gluonjs/core


@gluonjs/core / src / repeat

Function: repeat()

repeat<Item>(items, key, renderItem): RepeatResult

Renders an iterable with stable key-based identity.

Keys must be non-null strings, numbers, or symbols and unique within one result. Invalid keys throw while the result is created, before render() can mutate the DOM.

Type Parameters

Item

Item

Parameters

items

Iterable<Item>

key

(item, index) => PropertyKey

renderItem

(item, index) => TemplateValue

Returns

RepeatResult

Example

Render a collection with stable unique keys so insertions, removals, and moves retain the correct DOM identity:

ts
import {
  TemplateResult,
  directive,
  elementRef,
  event,
  html,
  hydrate,
  render,
  repeat,
  suspendRender,
  svg,
  unsafeHTML,
  unsafeURL,
  type DirectiveValue,
  type EventBinding,
  type RefTarget,
  type RepeatResult,
  type UnsafeHtmlResult,
  type UnsafeUrlResult,
} from '@gluonjs/core';
import { prepareForHydration } from '@gluonjs/ssr';

const products = [{ id: 'lamp', name: 'Orbit Lamp' }, { id: 'tray', name: 'Stack Tray' }];
const rows: RepeatResult = repeat(products, (product) => product.id, (product) => html`<li>${product.name}</li>`);
const click: EventBinding = event(() => console.log('saved'), { once: true });
const buttonRef: RefTarget<HTMLButtonElement> = elementRef<HTMLButtonElement>();
const trustedDescription: UnsafeHtmlResult = unsafeHTML('<strong>In stock</strong>');
const trustedManual: UnsafeUrlResult = unsafeURL('https://example.com/manual.pdf');
const text = directive<readonly [string]>((value) => (part) => part.setValue(value));
const status: DirectiveValue = text('Ready');
const icon = svg`<svg viewBox='0 0 10 10'><circle cx='5' cy='5' r='4'></circle></svg>`;
const template: TemplateResult = html`
  <section>${icon}<ul>${rows}</ul>${trustedDescription}
    <a href=${trustedManual}>Manual</a>
    <button ...=${{ ref: buttonRef }} @click=${click}>${status}</button>
  </section>
`;

const clientRoot = document.createElement('div');
render(template, clientRoot);
suspendRender(clientRoot);
render(template, clientRoot);
const prepared = await prepareForHydration(template);
if (!(prepared.value instanceof TemplateResult)) throw new Error('Expected one template root');
const hydrationRoot = document.createElement('div');
hydrationRoot.innerHTML = prepared.html;
const hydration = hydrate(prepared.value, hydrationRoot, { expectedMarkup: prepared.html });
console.log(hydration.retained, rows.items.length, buttonRef.value, trustedDescription.markup, trustedManual.value);