Back to blog

Add closing animation to Intercepting Route modal using Next.js

Since Next.js doesn’t support exit animations yet (Relevant issue), we need to manually create the animation event.

For this example I’m using the Sheet component from shadcn/ui, but you can use the Dialog from Radix directly with your own style.

Initial modal component

This is our initial component using shadcn/ui Drawer component, based on the Next.js docs.

app/components/modal.tsx
"use client";
import { useRouter } from "next/navigation";
import { Sheet, SheetContent } from "@/components/ui/sheet";
export default function Modal({ children }: { children: React.ReactNode }) {
const router = useRouter();
function handleClose() {
router.back();
}
return (
<Sheet open onOpenChange={handleClose}>
<SheetContent
side="bottom"
className="h-full overflow-auto rounded-t-3xl px-0 py-16 md:h-[96%]"
>
{children}
</SheetContent>
</Sheet>
);
}

Where we just call the router.back() to close the modal.

Adding a closing animation

To achieve this, we need to control the open state to perform the router.back() after the closing animation ends, using onAnimationEndCapture.

app/components/modal.tsx
"use client";
import { useRouter } from "next/navigation";
import { Sheet, SheetContent } from "@/components/ui/sheet";
import { useState } from "react";
export default function Modal({ children }: { children: React.ReactNode }) {
const [open, setOpen] = useState(true);
const router = useRouter();
function handleClose() {
router.back();
setOpen(false);
}
function handleAnimationEnd() {
// when the modal animation ends: if it's closed, navigate back
if (!open) {
router.back();
}
}
return (
<Sheet open={open} onOpenChange={handleClose}>
<SheetContent
onAnimationEndCapture={handleAnimationEnd}
side="bottom"
className="h-full overflow-auto rounded-t-3xl px-0 py-16 md:h-[96%]"
>
{children}
</SheetContent>
</Sheet>
);
}

Result

Now when pressing the close button or the ESC key, the modal will exit with an animation then go back to the previous URL.

We still can’t animate when the React component is unmounted (eg: when using the browser’s back button), for that we’ll have to wait for native framework support.

For now this cover the rest of usecases.