fix: recreate observer when root changes to a same-tag element#155
Merged
Conversation
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
Bot
temporarily deployed
to
metonym/fix-observer-root-identity - svelte-intersection-observer PR #155
July 5, 2026 20:21
Destroyed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.