Skip to content

fix: recreate observer when root changes to a same-tag element#155

Merged
metonym merged 1 commit into
masterfrom
metonym/fix-observer-root-identity
Jul 5, 2026
Merged

fix: recreate observer when root changes to a same-tag element#155
metonym merged 1 commit into
masterfrom
metonym/fix-observer-root-identity

Conversation

@metonym

@metonym metonym commented Jul 5, 2026

Copy link
Copy Markdown
Owner

The observer re-init key in both IntersectionObserver.svelte and MultipleIntersectionObserver.svelte was built by string-interpolating root along with rootMargin and threshold. An HTMLElement stringifies to its tag form, e.g. "[object HTMLDivElement]", so swapping root between two elements of the same tag (two divs, for example) produced an identical key. The effect that tears down and recreates the native IntersectionObserver never re-ran, and the observer kept measuring intersections against the old root element.

The fix narrows the derived key to the value-typed options (rootMargin and threshold) and reads root directly in the re-init effect body, outside untrack, so a reference change to root now correctly triggers teardown and recreation. initialize() already read root when constructing the observer, so no change was needed there. The intersect action was already comparing root by reference and is unaffected.

Added unit tests for both components that swap root between two same-tag containers and assert a new observer instance is created, the old one is disconnected, and elements are re-observed against the new root. Confirmed the tests fail against the pre-fix code and pass after the fix. Full unit, type-check, lint, and e2e suites pass.

Risk is low and scoped to the reactive wiring around root changes. Anyone relying on the old (buggy) behavior where changing root to a same-tag element silently kept the previous root would see a behavior change, but that behavior was never intentional or documented.

The observer re-init key stringified `root`, and an element stringifies
to "[object HTMLDivElement]" — so swapping `root` between two elements
of the same tag produced an identical key and the observer kept
measuring against the old root. Compare `root` by reference in the
re-init effect instead, and key only the value-typed options
(rootMargin, threshold).

Affects both IntersectionObserver and MultipleIntersectionObserver.
The intersect action already compared root by reference.
@render
render Bot temporarily deployed to metonym/fix-observer-root-identity - svelte-intersection-observer PR #155 July 5, 2026 20:21 Destroyed
@metonym
metonym merged commit c3944d6 into master Jul 5, 2026
3 checks passed
@metonym
metonym deleted the metonym/fix-observer-root-identity branch July 5, 2026 20:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant