You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: add onexit callback to all primitives (#157)
Completes the enter/leave pair: onintersect fires on intersecting
entries, onexit fires when an element transitions out of view. The
initial off-screen report does not fire onexit — exit means "was in
view, no longer is", tracked per element.
- IntersectionObserver / MultipleIntersectionObserver: onexit prop
- intersect / intersectAttachment: "exit" CustomEvent (onexit handler
typed via the svelte/elements augmentation)
- createIntersectionGroup: per-node onexit option
- previous-state tracking resets when an observer is rebuilt (action
config change, group shared-option rebuild)
Every primitive shares the same core options (`root`, `rootMargin`, `threshold`, `once`, `skip`) and the same `onobserve`/`onintersect` callbacks. Only how you plug it into your markup differs. See [Use Cases](#use-cases) for realistic scenarios built from these.
52
+
Every primitive shares the same core options (`root`, `rootMargin`, `threshold`, `once`, `skip`) and the same `onobserve`/`onintersect`/`onexit` callbacks. Only how you plug it into your markup differs. See [Use Cases](#use-cases) for realistic scenarios built from these.
53
53
54
54
### `IntersectionObserver`
55
55
@@ -144,7 +144,7 @@ In this example, "Hello world" fades in when its containing element intersects t
144
144
145
145
#### Callback props
146
146
147
-
Same `onobserve`/`onintersect` behavior as described in [Callbacks](#callbacks-onobserve-and-onintersect) below.
147
+
Same `onobserve`/`onintersect`/`onexit` behavior as described in [Callbacks](#callbacks-onobserve-onintersect-and-onexit) below.
148
148
149
149
#### `children` snippet props
150
150
@@ -258,7 +258,7 @@ Called with:
258
258
}
259
259
```
260
260
261
-
See [Callbacks](#callbacks-onobserve-and-onintersect) for when each one fires.
261
+
See [Callbacks](#callbacks-onobserve-onintersect-and-onexit) for when each one fires.
262
262
263
263
#### `children` snippet props
264
264
@@ -270,7 +270,7 @@ See [Callbacks](#callbacks-onobserve-and-onintersect) for when each one fires.
270
270
271
271
### `intersect`
272
272
273
-
As an alternative to the `IntersectionObserver` component, use the `intersect` action to observe an element directly with `use:`, without a `bind:this` reference or extra markup. Listen for `onobserve`/`onintersect` on the observed element itself.
273
+
As an alternative to the `IntersectionObserver` component, use the `intersect` action to observe an element directly with `use:`, without a `bind:this` reference or extra markup. Listen for `onobserve`/`onintersect`/`onexit` on the observed element itself.
274
274
275
275
```svelte
276
276
<script lang="ts">
@@ -307,7 +307,7 @@ Options passed to `use:intersect` are reactive: updating `root`, `rootMargin`, o
307
307
308
308
#### Dispatched events
309
309
310
-
Same `onobserve`/`onintersect` behavior as described in [Callbacks](#callbacks-onobserve-and-onintersect); the action dispatches them on the element, and `e.detail` is the [`IntersectionObserverEntry`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry).
310
+
Same `onobserve`/`onintersect`/`onexit` behavior as described in [Callbacks](#callbacks-onobserve-onintersect-and-onexit); the action dispatches them on the element, and `e.detail` is the [`IntersectionObserverEntry`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry).
311
311
312
312
### `intersectAttachment`
313
313
@@ -417,7 +417,7 @@ const group = createIntersectionGroup(() => ({
417
417
418
418
Shared options are reactive: when `root`, `rootMargin`, or `threshold` changes, the group rebuilds its single shared observer and re-observes every element. Note that elements whose `once` has already fired are re-observed as well.
419
419
420
-
`once`, `skip`, `onobserve`, and `onintersect` are the only options that make sense per element, so those are what `group.attach(...)` accepts.
420
+
`once`, `skip`, `onobserve`, `onintersect`, and `onexit` are the only options that make sense per element, so those are what `group.attach(...)` accepts.
421
421
422
422
#### Signature
423
423
@@ -447,13 +447,15 @@ Passed once per element, to `group.attach(...)`.
447
447
| skip | Skip observing this element without affecting the group |`boolean`|`false`|
448
448
| onobserve | Called when the element is first observed or when an intersection change occurs |`(entry: IntersectionObserverEntry) => void`|`undefined`|
449
449
| onintersect | Called when the element is intersecting the viewport |`(entry: IntersectionObserverEntry) => void`|`undefined`|
450
+
| onexit | Called when the element stops intersecting |`(entry: IntersectionObserverEntry) => void`|`undefined`|
450
451
451
-
#### Callbacks: `onobserve`and `onintersect`
452
+
#### Callbacks: `onobserve`, `onintersect`, and `onexit`
452
453
453
-
Every primitive above exposes the same two callbacks, called with an [`IntersectionObserverEntry`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry) (components pass it directly; action and attachment dispatch it as `event.detail`):
454
+
Every primitive above exposes the same three callbacks, called with an [`IntersectionObserverEntry`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry) (components pass it directly; action and attachment dispatch it as `event.detail`):
454
455
455
456
-**onobserve**: called when the element is first observed, and again on every intersection change
456
457
-**onintersect**: called only when the element is intersecting the viewport (a filtered view of `onobserve`)
458
+
-**onexit**: called when the element stops intersecting (transitions out of view); not called for the initial off-screen report
457
459
458
460
```svelte no-eval
459
461
<IntersectionObserver
@@ -465,6 +467,9 @@ Every primitive above exposes the same two callbacks, called with an [`Intersect
@@ -495,7 +500,7 @@ Delay loading an image's real `src` until it's about to scroll into view. `rootM
495
500
496
501
### Autoplaying video
497
502
498
-
Play a `<video>` while it's on screen and pause it once it scrolls away. Unlike lazy-loading, this needs to react every time visibility changes, so use `onobserve`(not `onintersect`) and skip `once`.
503
+
Play a `<video>` while it's on screen and pause it once it scrolls away. Unlike lazy-loading, this needs to react every time visibility changes, so use the `onintersect`/`onexit` pair (not `onobserve`) and skip `once`.
499
504
500
505
```svelte no-eval
501
506
<script lang="ts">
@@ -507,9 +512,8 @@ Play a `<video>` while it's on screen and pause it once it scrolls away. Unlike
Copy file name to clipboardExpand all lines: src/IntersectionObserver.svelte
+10Lines changed: 10 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -14,6 +14,7 @@
14
14
* @property{boolean}[skip] Set to `true` to pause observing without disconnecting the observer or losing `entry`/`intersecting` state. Set back to `false` to resume.
15
15
* @property{(entry: IntersectionObserverEntry) => void}[onobserve] Called when the element is first observed and also whenever an intersection event occurs.
16
16
* @property{(entry: IntersectionObserverEntry & { isIntersecting: true }) => void}[onintersect] Called only when the observed element is intersecting the viewport.
17
+
* @property{(entry: IntersectionObserverEntry & { isIntersecting: false }) => void}[onexit] Called when the observed element transitions from intersecting to not intersecting. Not called for the initial off-screen report.
Copy file name to clipboardExpand all lines: src/MultipleIntersectionObserver.svelte
+11Lines changed: 11 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -14,6 +14,7 @@
14
14
* @property{boolean}[skip] Set to `true` to pause observing all elements without disconnecting the observer or losing `elementIntersections`/`elementEntries` state. Set back to `false` to resume.
15
15
* @property{(detail: { entry: IntersectionObserverEntry, target: Element }) => void}[onobserve] Called when an element is first observed and also whenever an intersection event occurs.
16
16
* @property{(detail: { entry: IntersectionObserverEntry & { isIntersecting: true }, target: Element }) => void}[onintersect] Called only when an element is intersecting the viewport.
17
+
* @property{(detail: { entry: IntersectionObserverEntry & { isIntersecting: false }, target: Element }) => void}[onexit] Called when an element transitions from intersecting to not intersecting. Not called for the initial off-screen report.
0 commit comments