Ref
Refs hold values that persist across renders without causing renders. pp.ref() creates one in the script; the pp-ref attribute binds a DOM element into one.
Value refs: state that should never repaint
Timers, request generations, pagination cursors and transient text are the
classic cases. Putting them in pp.state would schedule renders nobody
can see; a ref just stores them.
<section pp-component="search_box">
<input oninput="onType(target.value)" placeholder="Search…" />
<ul>
<template pp-for="hit in results">
<li key="{hit.id}">{hit.title}</li>
</template>
</ul>
<script>
const [results, setResults] = pp.state([]);
// Render-free values: the debounce timer and the request generation.
const timer = pp.ref(null);
const generation = pp.ref(0);
const onType = (text) => {
clearTimeout(timer.current);
timer.current = setTimeout(async () => {
const mine = ++generation.current;
const hits = await pp.rpc("search", { query: text });
if (mine === generation.current) setResults(hits); // drop stale responses
}, 250);
};
</script>
</section>
DOM refs: imperative element access
Add pp-ref="name" to an element and declare const name = pp.ref(null)
in the script. After mount, name.current is the live element.
<section pp-component="video_player">
<video pp-ref="playerRef" src="/media/intro.mp4"></video>
<button onclick="playerRef.current.play()">Play</button>
<button onclick="playerRef.current.pause()">Pause</button>
<script>
const playerRef = pp.ref(null);
</script>
</section>
Callback refs
pp-ref="{expr}" also accepts a function. It is called with the element
when it attaches; if it returns a function, PulsePoint runs that as cleanup when
the ref is replaced or the element detaches.
<div pp-ref="{(el) => {
const observer = new ResizeObserver(onResize);
observer.observe(el);
return () => observer.disconnect(); // cleanup on detach
}}"></div>
Rules
- Mutating
ref.currentnever triggers a render. If the UI must react, the value belongs in state. - Read DOM refs in effects or handlers — not during render, where the element may not exist yet.
pp-refworks on component roots too; pair it withpp.imperativeHandlein the child to publish a curated API instead of the raw node.- Do not reach for refs plus
addEventListenerto wire events the template can bind withon*attributes — that duplicates what the runtime already does declaratively.