Skip to content

Pagination with scroll to

This example shows a paginated list that scrolls back to the top whenever the page changes, improving the user experience.

To archieve this we leverage Crelte's data attributes and an event.

App.svelte:

svelte
<script module>
	// this should be in a plugin or in the app.init function
	export function init(crelte) {
		// todo onRequest we could also already disable the scroll
		// so the attribute data-disable-scroll does not need to be added

		// after render gets excuted once the new dom was rendered
		crelte.events.on('afterRender', (cr, route) => {
			// all data-* are stored inside the context
			const scrollTo = route.getContext('scrollTo');
			if (scrollTo) {
				const el = document.querySelector(scrollTo);
				el?.scrollIntoView({ behavior: 'smooth' });
			}
		});
	}
</script>

PaginatedList.svelte:

svelte
<script module>
	/** @type {import('crelte').LoadData} */
	export const loadData = ({ req }) => {
		const page = parseInt(req.getSearchParam('page')) || 0;

		// this could of course also be a query
		const content = Array(10).fill(0).map((_, i) => `Item ${page * 10 + i}`);

		return { page, content };
	};
</script>

<script>
	import { getRoute } from 'crelte';

	let { page, content } = $props();

	function paginatedUrl(route, page) {
		route.setSearchParam('page', page > 0 ? page : null);
		return route.url;
	}
</script>

<div id="list">
	{#each content as item}
		<div class="item">{item}</div>
	{/each}
</div>

<div class="navigation">
	{#if page > 0}
		<a
			href={paginatedUrl($route, page - 1)}
			data-disable-scroll
			data-scroll-to="#list"
		>Previous page</a>
	{/if}
	<a
		href={paginatedUrl($route, page + 1)}
		data-disable-scroll
		data-scroll-to="#list"
	>Next page</a>
</div>

<style lang="scss">
	.item {
		min-height: 20vh;
	}
</style>