Animated change between pages/views.
fade transition · 900ms between routes
<div class="mot-pgt-stage" data-style="fade">
<div class="mot-pgt-page mot-pgt-page--a mot-pgt-page--cycle" style="background:#BFD9F2;">Page A</div>
<div class="mot-pgt-page mot-pgt-page--b mot-pgt-page--cycle">Page B</div>
<p class="mot-pgt-caption">fade transition · 900ms between routes</p>
</div>
<style>
.mot-pgt-stage { position: relative; width: 100%; max-width: 320px; height: 100px; background: #FAF7F2; border: 1px solid #24143022; border-radius: 12px; overflow: hidden; font: 13px system-ui, sans-serif; color: #241430aa; }
.mot-pgt-page { position: absolute; inset: 0; display: grid; place-items: center; font-weight: 700; color: #241430; }
.mot-pgt-page--b { background: #FAF7F2; border: 2px dashed #24143033; opacity: 0; }
.mot-pgt-caption { position: absolute; bottom: -26px; left: 0; }
@media (prefers-reduced-motion: no-preference) {
[data-style="fade"] .mot-pgt-page--cycle.mot-pgt-page--a { animation: mot-pgt-fade-out 900ms ease-in-out infinite; }
[data-style="fade"] .mot-pgt-page--cycle.mot-pgt-page--b { animation: mot-pgt-fade-in 900ms ease-in-out infinite; }
[data-style="slide"] .mot-pgt-page--cycle.mot-pgt-page--a { animation: mot-pgt-slide-out 900ms ease-in-out infinite; }
[data-style="slide"] .mot-pgt-page--cycle.mot-pgt-page--b { animation: mot-pgt-slide-in 900ms ease-in-out infinite; }
[data-style="scale"] .mot-pgt-page--cycle.mot-pgt-page--a { animation: mot-pgt-scale-out 900ms ease-in-out infinite; }
[data-style="scale"] .mot-pgt-page--cycle.mot-pgt-page--b { animation: mot-pgt-scale-in 900ms ease-in-out infinite; }
@keyframes mot-pgt-fade-out { 0%,45% { opacity: 1; } 50%,100% { opacity: 0; } }
@keyframes mot-pgt-fade-in { 0%,45% { opacity: 0; } 50%,95% { opacity: 1; } 100% { opacity: 0; } }
@keyframes mot-pgt-slide-out { 0%,45% { transform: translateX(0); } 50%,100% { transform: translateX(-100%); } }
@keyframes mot-pgt-slide-in { 0%,45% { transform: translateX(100%); opacity: 1; } 50%,95% { transform: translateX(0); opacity: 1; } 100% { transform: translateX(100%); } }
@keyframes mot-pgt-scale-out { 0%,45% { opacity: 1; transform: scale(1); } 50%,100% { opacity: 0; transform: scale(1.15); } }
@keyframes mot-pgt-scale-in { 0%,45% { opacity: 0; transform: scale(.85); } 50%,95% { opacity: 1; transform: scale(1); } 100% { opacity: 0; } }
}
</style><div class="relative w-full max-w-[320px] h-[100px] bg-[#FAF7F2] border border-[#24143022] rounded-xl overflow-hidden font-sans text-sm text-[#241430]/70" data-style="fade">
<div class="tw-pgt-a tw-pgt-cycle absolute inset-0 grid place-items-center font-bold text-[#241430]" style="background:#BFD9F2;">Page A</div>
<div class="tw-pgt-b tw-pgt-cycle absolute inset-0 grid place-items-center font-bold text-[#241430] bg-[#FAF7F2] border-2 border-dashed border-[#24143033] opacity-0">Page B</div>
<p class="absolute -bottom-6 left-0">fade transition · 900ms between routes</p>
</div>
<style>
@media (prefers-reduced-motion: no-preference) {
[data-style="fade"] .tw-pgt-cycle.tw-pgt-a { animation: mot-pgt-tw-fade-out 900ms ease-in-out infinite; }
[data-style="fade"] .tw-pgt-cycle.tw-pgt-b { animation: mot-pgt-tw-fade-in 900ms ease-in-out infinite; }
[data-style="slide"] .tw-pgt-cycle.tw-pgt-a { animation: mot-pgt-tw-slide-out 900ms ease-in-out infinite; }
[data-style="slide"] .tw-pgt-cycle.tw-pgt-b { animation: mot-pgt-tw-slide-in 900ms ease-in-out infinite; }
[data-style="scale"] .tw-pgt-cycle.tw-pgt-a { animation: mot-pgt-tw-scale-out 900ms ease-in-out infinite; }
[data-style="scale"] .tw-pgt-cycle.tw-pgt-b { animation: mot-pgt-tw-scale-in 900ms ease-in-out infinite; }
@keyframes mot-pgt-tw-fade-out { 0%,45% { opacity: 1; } 50%,100% { opacity: 0; } }
@keyframes mot-pgt-tw-fade-in { 0%,45% { opacity: 0; } 50%,95% { opacity: 1; } 100% { opacity: 0; } }
@keyframes mot-pgt-tw-slide-out { 0%,45% { transform: translateX(0); } 50%,100% { transform: translateX(-100%); } }
@keyframes mot-pgt-tw-slide-in { 0%,45% { transform: translateX(100%); opacity: 1; } 50%,95% { transform: translateX(0); opacity: 1; } 100% { transform: translateX(100%); } }
@keyframes mot-pgt-tw-scale-out { 0%,45% { opacity: 1; transform: scale(1); } 50%,100% { opacity: 0; transform: scale(1.15); } }
@keyframes mot-pgt-tw-scale-in { 0%,45% { opacity: 0; transform: scale(.85); } 50%,95% { opacity: 1; transform: scale(1); } 100% { opacity: 0; } }
}
</style>export function PageTransition({
style = "fade",
duration = 900,
loop = true,
accent = "#BFD9F2",
}) {
const cls = loop ? "cycle" : "";
return (
<div style={{ position: "relative", width: "100%", maxWidth: 320, height: 100, background: "#FAF7F2", border: "1px solid #24143022", borderRadius: 12, overflow: "hidden", fontFamily: "system-ui, sans-serif", fontSize: 13, color: "#241430aa" }}>
<div className={`page-a ${cls}`} style={{ position: "absolute", inset: 0, display: "grid", placeItems: "center", fontWeight: 700, color: "#241430", background: accent }}>Page A</div>
<div className={`page-b ${cls}`} style={{ position: "absolute", inset: 0, display: "grid", placeItems: "center", fontWeight: 700, color: "#241430", background: "#FAF7F2", border: "2px dashed #24143033", opacity: 0 }}>Page B</div>
<p style={{ position: "absolute", bottom: -26, left: 0 }}>{style} transition · {duration}ms between routes</p>
<style>{`
@media (prefers-reduced-motion: no-preference) {
[data-style="fade"] .page-a.cycle, .fade-a { animation: mot-pgt-fade-out ${duration}ms ease-in-out infinite; }
.page-a.cycle { animation: ${style === "fade" ? "mot-pgt-fade-out" : style === "slide" ? "mot-pgt-slide-out" : "mot-pgt-scale-out"} ${duration}ms ease-in-out infinite; }
.page-b.cycle { animation: ${style === "fade" ? "mot-pgt-fade-in" : style === "slide" ? "mot-pgt-slide-in" : "mot-pgt-scale-in"} ${duration}ms ease-in-out infinite; }
@keyframes mot-pgt-fade-out { 0%,45% { opacity: 1; } 50%,100% { opacity: 0; } }
@keyframes mot-pgt-fade-in { 0%,45% { opacity: 0; } 50%,95% { opacity: 1; } 100% { opacity: 0; } }
@keyframes mot-pgt-slide-out { 0%,45% { transform: translateX(0); } 50%,100% { transform: translateX(-100%); } }
@keyframes mot-pgt-slide-in { 0%,45% { transform: translateX(100%); opacity: 1; } 50%,95% { transform: translateX(0); opacity: 1; } 100% { transform: translateX(100%); } }
@keyframes mot-pgt-scale-out { 0%,45% { opacity: 1; transform: scale(1); } 50%,100% { opacity: 0; transform: scale(1.15); } }
@keyframes mot-pgt-scale-in { 0%,45% { opacity: 0; transform: scale(.85); } 50%,95% { opacity: 1; transform: scale(1); } 100% { opacity: 0; } }
}
`}</style>
</div>
);
}