Columns Page Transition

Page Transition
GSAP
JS
Last Updated: Jan 6, 2026
  • To avoid flicker, the transition should be one of the first elements on the page.
<style>
html:not(.transition-1-first-visit).w-mod-js .transition-1_component {
	display: flex;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/gsap.min.js"></script>
<script>
if (!sessionStorage.getItem("transition-1-first-visit")) {
	sessionStorage.setItem("transition-1-first-visit", "viewed");
	document.documentElement.classList.add("transition-1-first-visit");
}
document.addEventListener("DOMContentLoaded", () => {
	document.querySelectorAll(".transition-1_component").forEach((component) => {
		if (component.hasAttribute("data-transition-1")) return;
		component.setAttribute("data-transition-1", "");

		document.addEventListener("click", (e) => {
			const link = e.target.closest("a");
			if (!link) return;
			const currentUrl = link.href;
			if (link.hostname !== window.location.host || currentUrl.includes("#") || link.target === "_blank") return;
			e.preventDefault();
			gsap.context(() => {
				let tl = gsap.timeline({ onComplete: () => window.location.href = currentUrl });
				tl.set(component, { display: "flex" });
				tl.fromTo(".transition-1_column", { yPercent: 100 }, { yPercent: 0, duration: 0.3, ease: "power1.inOut", stagger: { each: 0.1, from: "start" } });
			}, component);
		});
		window.onpageshow = e => e.persisted && window.location.reload();

		if (document.documentElement.classList.contains("transition-1-first-visit")) return;
		gsap.context(() => {
			let tl = gsap.timeline();
			tl.set(component, { display: "flex" });
			tl.to(".transition-1_column", { yPercent: -100, duration: 0.3, ease: "power1.inOut", stagger: { each: 0.1, from: "start" } });
			tl.set(component, {display: "none"});
		}, component);

	});
});
</script>