scrollX/Y for things other than window
Is there a reason why there's no bind:scrollX for dom nodes ? I see there are for window. I rolled my own solution, but it felt like it should be supported!
What would these measure? Which DOM properties are you referring to?
dom.scrollLeft and dom.scrollTop
So e.g if I want to programmatically set scrollLeft of a dom element from a reactive property or tweenable store prop.
I like this, I've wanted it a couple of times myself. Opened #3895. It uses scrollLeft and scrollTop as the binding names, rather than making it consistent with <svelte:window> but inconsistent with the DOM
+1 for wanting bind:scrollLeft/bind:scrollTop.
@Rich-Harris I saw that you identified some issues with your initial implementation approach. I could take a crack at fixing it, if you can point me in the right direction.
We've been wanting this feature as well, to implement a scroll carousel functionality using CSS scroll snapping on a PWA. But the app needs to know the current scroll position!
What would you folks recommend as an interim solution? Would it be something like element.addEventListener("scroll", ...)?
Would love an interim solution if anyone worked one out!
This would've been nice.
I thought it's already implemented since we have it for <svelte:window>.
Requires a few lines, but falling back to EventListeners this is the best I could come up with, using bind:
<script>
import { onMount } from 'svelte';
let elem;
let elemScrollTop = 0; // This will be reactive
onMount(() => {
// Update elemScrollTop every time the user scrolls
elem.addEventListener('scroll', ({ target }) => (elemScrollTop = target.scrollTop));
});
</script>
<div bind:this={elem}></div>
I couldn't figure out a solution leveraging svelte's reactivity to update scrollTop/scrollLeft. If someone finds a better solution I'd love to know too.
This would be a massive feature for my project. We have an in-house carousel that we've built, and it's extremely complex because we had to implement part of this ourselves.
I couldn't figure out a solution leveraging svelte's reactivity to update
scrollTop/scrollLeft. If someone finds a better solution I'd love to know too.
What about
<script>
let elem;
let elemScrollTop = 0;
</script>
<div bind:this={elem} on:scroll={() => (elemScrollTop = elem.scrollTop)}></div>
or
<script>
let elemScrollTop = 0;
</script>
<div on:scroll={(ev) => (elemScrollTop = ev.target.scrollTop)}></div>
?
In case you're trying to find out whether an element entered or left the viewport, I found the nice svelte-inview action. However support of scrollX / scrollY for any element would be greatly appreciated.
Here's my little action :
const scrollLeft = writable(0)
export function scrollX(node, store) {
store.subscribe(val => node.scrollLeft = val)
node.addEventListener('scroll', (e) => {
store.set(e.target.scrollLeft)
})
}
use like:
<div use:scrollX={scrollLeft}> ...
guys, any updates on this?
This would be very useful for triggering an animation when a child element becomes visible!
A workaround I came up with for Svelte 5 runes
let scrollY = $state(0)
...
const bindScrollY = (node: HTMLElement, val: { scrollY: number }) => {
$effect(() => {
node.scrollTop = scrollY
})
const handle = (e: any) => {
scrollY = e.target.scrollTop
}
node.addEventListener('scroll', handle)
return {
destroy: () => removeEventListener('scroll', handle)
}
}
...
<div ... use:bindScrollY={{ scrollY }}>