useScroll

Reactive scroll position and state.

Ported from vueuse/useScroll

Example #

TopLeft
BottomLeft
TopRight
BottomRight
Scroll Me
X Position
Y Position
Smooth isScrolling false
Top Arrived
true
Right Arrived
false
Bottom Arrived
false
Left Arrived
true
Scrolling Up
false
Scrolling Right
false
Scrolling Down
false
Scrolling Left
false
  • Svelte
<script lang="ts">
	import { useDebounceFn, useScroll } from 'sveltuse'

	import BooleanDisplay from 'app/components/BooleanDisplay.svelte'
	import { Input } from 'flowbite-svelte'

	let el: HTMLElement
	let smooth = false

	const { x, y, isScrolling, arrivedState, directions } = useScroll(() => el, {
		behavior: () => (smooth ? 'smooth' : 'auto')
	})
</script>

<div class="flex">
	<div
		bind:this={el}
		class="w-[300px] h-[300px] m-auto overflow-scroll bg-gray-800 rounded">
		<div class="w-[600px] h-[600px] relative">
			<div class="p-3 x-2 y-1 bg-gray-700 absolute left-0 top-0">
				TopLeft
			</div>
			<div class="p-3 x-2 y-1 bg-gray-700 absolute left-0 bottom-0">
				BottomLeft
			</div>
			<div class="p-3 x-2 y-1 bg-gray-700 absolute right-0 top-0">
				TopRight
			</div>
			<div class="p-3 x-2 y-1 bg-gray-700 absolute right-0 bottom-0">
				BottomRight
			</div>
			<div class="p-3 x-2 y-1 bg-gray-700 absolute left-1/3 top-1/3">
				Scroll Me
			</div>
		</div>
	</div>
	<div class="m-auto w-280px pl-4">
		<div
			class="px-6 py-4 rounded grid grid-cols-[120px_auto] gap-2 bg-gray-500/5">
			<div class="flex items-center col-span-2 space-x-1">
				<span class="text-right opacity-75 flex-none">X Position</span>
				<Input
					value={Math.round($x)}
					min="0"
					max="800"
					step="100"
					type="number"
					on:input={useDebounceFn((e) => {
						x.set(+e.target.value)
					}, 200)} />
			</div>

    		<div class="flex items-center col-span-2 space-x-1">
    			<span class="text-right opacity-75 flex-none">Y Position</span>
    			<Input
    				value={Math.round($y)}
    				min="0"
    				max="800"
    				step="100"
    				type="number"
    				on:input={useDebounceFn((e) => {
    					y.set(+e.target.value)
    				}, 200)} />
    		</div>

    		<span class="text-right opacity-75">Smooth</span>
    		<input
    			class="mt-1"
    			type="checkbox"
    			checked={smooth}
    			on:input={(e) => (smooth = e.target.checked)} />

    		<span class="text-right opacity-75">isScrolling</span>
    		<BooleanDisplay value={$isScrolling} />
    		<div class="text-right opacity-75">Top Arrived</div>
    		<BooleanDisplay value={$arrivedState.top} />
    		<div class="text-right opacity-75">Right Arrived</div>
    		<BooleanDisplay value={$arrivedState.right} />
    		<div class="text-right opacity-75">Bottom Arrived</div>
    		<BooleanDisplay value={$arrivedState.bottom} />
    		<div class="text-right opacity-75">Left Arrived</div>
    		<BooleanDisplay value={$arrivedState.left} />
    		<div class="text-right opacity-75">Scrolling Up</div>
    		<BooleanDisplay value={$directions.top} />
    		<div class="text-right opacity-75">Scrolling Right</div>
    		<BooleanDisplay value={$directions.right} />
    		<div class="text-right opacity-75">Scrolling Down</div>
    		<BooleanDisplay value={$directions.bottom} />
    		<div class="text-right opacity-75">Scrolling Left</div>
    		<BooleanDisplay value={$directions.left} />
    	</div>
    </div>
</div>

Usage #

<script lang="ts">
import { useScroll } from 'sveltuse'

let el: HTMLElement
const { x, y, isScrolling, arrivedState, directions } = useScroll(() => el)
</script>

<div bind:this={el}></div>

With offsets #

const { x, y, isScrolling, arrivedState, directions } = useScroll(el, {
	offset: { top: 30, bottom: 30, right: 30, left: 30 }
})

Setting scroll position #

Set the x and y values to make the element scroll to that position.

<script lang="ts">
	import { Button } from 'flowbite-svelte'
	import { useScroll } from 'sveltuse'

	let el: HTMLElement
	const { x, y } = useScroll(() => el)
</script>

<div>
	<div bind:this={el} class="mb-4 overflow-auto h-32 w-full bg-gray-700">
		<div class="h-[2400px] w-[2400px]" />
	</div>
	<Button on:click={() => x.update((x) => x + 100)}>Scroll right 100px</Button>
	<Button on:click={() => y.update((y) => y + 100)}>Scroll down 100px</Button>
</div>

Directive Usage #

<script lang="ts">
	import { dScroll, type UseScrollReturn } from 'sveltuse'

	const onScroll = (e: UseScrollReturn) => {
		console.log('onScroll', e)
	}
</script>

<div use:dScroll={onScroll} class="mb-4 overflow-auto h-32 w-full bg-gray-700">
	<div class="h-[2400px] w-[2400px]" />
</div>

Source #