Skip to content

Visibility

The visibility source is scroll-triggered, not scroll-linked. It writes two binary signals per bound element: --live-visible (1 while the whole element is on screen) and --const-has-entered (latches to 1 once the element is entirely in view, never resets). The continuous ratio is left to native view() timelines; the one-way latch is the part those can’t express. Scroll the panels below into and out of view.

i in view entered

--live-visible is 1 while the whole element is on screen.

ii in view entered

--const-has-entered latches once the element is entirely in view and never resets.

iii in view entered

So it reveals once and stays. Scroll back up; it won't reverse.

Each panel opts in with its own attribute — no list to query, and panels added later are picked up automatically:

<script type="module">import 'prop-for-that/auto'</script>
<section data-props-for="visibility"></section>
<section data-props-for="visibility"></section>
/* reveal once, then keep it */
.panel {
opacity: calc(0.25 + var(--const-has-entered) * 0.75);
transition: opacity 0.5s;
}
/* the dot lights only while in view */
.dot {
background: color-mix(in oklab, var(--accent) calc(var(--live-visible) * 100%), gray);
}