Great question! Preserving scroll position with Infinite Scroll when navigating away and back is an important UX consideration. Here is a well-structured solution for Laravel/Inertia/Vue:
1. Save Scroll Position Before Navigating
When the user clicks a game to view details, save the current scroll position and page state (including loaded items if possible).
In Your Infinite List Component
Add this before navigation (e.g., in your @click handler):
methods: {
goToGame(gameId) {
// Save scroll state to localStorage (or Pinia/Store/Reactively as needed)
localStorage.setItem('games_scroll_position', window.scrollY)
// Save items loaded so far (optional, but helps avoid re-fetching)
localStorage.setItem('games_list_state', JSON.stringify(this.games))
this.$inertia.visit(`/games/${gameId}`)
}
}
2. Restore Scroll Position When Returning
When the games list component is mounted, restore the state.
mounted() {
// Optional: Restore loaded games state
const gamesState = localStorage.getItem('games_list_state')
if (gamesState && !this.games.length) {
this.games = JSON.parse(gamesState)
}
// Restore scroll position after DOM updates
this.$nextTick(() => {
const pos = +localStorage.getItem('games_scroll_position') || 0
window.scrollTo({ top: pos, behavior: 'auto' })
})
}
Tip: Clean up state after use (in beforeDestroy/unmounted) to avoid quirks if the user visits directly.
3. Option: Use Inertia preserveState
If pagination/scroll state is embedded in your Vue component's state, you could also benefit from [Inertia's preserveState] and preserveScroll options. For example:
this.$inertia.visit('/games', {
// These help preserve scroll/component state automatically in some cases
preserveState: true,
preserveScroll: true,
})
But, with infinite scroll, manual scroll restoration like above is usually more reliable because the component is remounted and loses state unless actively preserved.
4. Handling Infinite Scroll Pagination
If your infinite scroll loads items from the API as the user scrolls, restoring only the scroll position is not enough—you must also restore the correct batch of items (games). That's why we save the loaded items array above. If your API supports querying by offset/page, use that info in the localStorage as well.
Summary
- Save the scroll position and loaded items to localStorage (or a Vuex/Pinia store).
- Restore them on mount of the games list component.
- Clear the saved position/state after restoring to prevent using stale data.
- Make sure your infinite scroll logic supports rehydrating the loaded items.
Example Minimal Implementation
<template>
<div>
<game-card
v-for="game in games"
:key="game.id"
@click="goToGame(game.id)"
/>
<!-- Infinite loader goes here -->
</div>
</template>
<script>
export default {
data() {
return {
games: []
}
},
mounted() {
const gamesState = localStorage.getItem('games_list_state')
if (gamesState && !this.games.length) {
this.games = JSON.parse(gamesState)
}
this.$nextTick(() => {
const pos = +localStorage.getItem('games_scroll_position') || 0
window.scrollTo({ top: pos, behavior: 'auto' })
})
},
methods: {
goToGame(gameId) {
localStorage.setItem('games_scroll_position', window.scrollY)
localStorage.setItem('games_list_state', JSON.stringify(this.games))
this.$inertia.visit(`/games/${gameId}`)
}
}
}
</script>
Let me know if you have a Pinia/Vuex store or need a store-based example!