Answer
Use sessionStorage to save the values you need before the view‑transition swap and restore them after the new page is mounted, hooking into Astro’s documented navigation events.
Confirmed facts
transition:persist only preserves DOM elements that match by ID or class; it does not persist scroll offsets or non‑island state.
- Astro’s ClientRouter emits the lifecycle events
astro:before-swap, astro:after-swap and astro:page-load (the latter runs after islands are re‑hydrated). There is no built‑in hook for generic JavaScript state or scroll positions.
- Data stored in
sessionStorage survives a client‑side navigation and is cleared when the tab closes.
Likely explanation
Because the framework does not automatically save scroll positions or arbitrary state, you must manually capture that information just before the DOM is replaced and re‑apply it after the new page has been prepared. This avoids duplicate listeners and memory‑leak‑like symptoms from third‑party scripts.
Steps to implement
- Identify the data to persist: e.g., the
scrollTop of a nested container and any ad‑hoc JavaScript values.
- Save the data in a listener for
astro:before-swap (fires before the old DOM is removed).
function saveState() {
const container = document.querySelector('#nested-scroll');
if (container) {
sessionStorage.setItem('nestedScrollTop', container.scrollTop.toString());
}
// Example of arbitrary state
sessionStorage.setItem('appState', JSON.stringify({ foo: 'bar' }));
}
window.addEventListener('astro:before-swap', saveState);
- Restore the data in a listener for
astro:page-load (fires after islands are re‑hydrated).
function restoreState() {
const top = sessionStorage.getItem('nestedScrollTop');
if (top !== null) {
const container = document.querySelector('#nested-scroll');
if (container) {
container.scrollTop = parseInt(top, 10);
}
}
const raw = sessionStorage.getItem('appState');
if (raw !== null) {
try {
const state = JSON.parse(raw);
// re‑apply your ad‑hoc logic here
} catch (_) { /* ignore corrupted data */ }
}
}
window.addEventListener('astro:page-load', restoreState);
- For third‑party scripts that expect a full page load, expose an
init() and teardown() pair. Call teardown() in the astro:before-swap handler and init() in the astro:page-load handler to avoid duplicate listeners or timers.
Missing diagnostic detail
Do the nested containers you wish to preserve have stable IDs or class names that remain unchanged across the source and destination pages? If they do, you could also rely on transition:persist for the container element itself, but the scroll offset would still need the manual restore shown above.