Back to Dictionary
Page & View Transitions
●○○Ready to Use
Use sparingly

Modal Enter / Exit

Choose modal motion when the interaction should pause the page without feeling like a new page.

Use

Focused decisions, compact editing flows, and confirmations that should preserve page context.

Avoid

Avoid for long workflows, full-page forms, or navigation that deserves its own route.

Safer Alternative

Fade Transition

Risk Level

High attention

Timing

Backdrop fade around 150-220ms; modal scale/fade around 180-260ms.

Easing

Use ease-out or a restrained spring on entry; avoid bouncy exits for serious tasks.

Risk

distractionaccessibility sensitive

Live Demo

What It Is

A combination of a fading background overlay and a modal window that scales and fades into the center of the viewport.

Decision Guidance

Choose modal motion when the interaction should pause the page without feeling like a new page.

Best For

Focused decisions, compact editing flows, and confirmations that should preserve page context.

Avoid When

Avoid for long workflows, full-page forms, or navigation that deserves its own route.

Timing

Backdrop fade around 150-220ms; modal scale/fade around 180-260ms.

Easing

Use ease-out or a restrained spring on entry; avoid bouncy exits for serious tasks.

Risk Tags

distractionaccessibility sensitive

When to Use

  • Confirmations and alerts
  • Editing details in a dashboard
  • Sign-in prompts

When NOT to Use

  • Full-page takeovers (use slide instead)

Configuration Tips

  • 01Modal should initial from scale 0.95 and opacity 0
  • 02Backsplash should fade in (opacity 0 to 0.5) over 200ms

You've Seen It In

TwitterNotionLinear

AI Implementation Prompts

Move from a fast scaffold to production details, then tune timing and edge states.

Animate this popup modal. The background should fade to dark, and the modal card should scale up slightly and fade in exactly in the middle.

Reference Implementation

The same implementation approach used by the live preview, kept compact enough to inspect and adapt.

'use client';
import { motion, AnimatePresence } from 'framer-motion';
import { useState, useEffect } from 'react';

export function ModalEnterExitDemo({ isPlaying = false }: { isPlaying?: boolean }) {
    const [isOpen, setIsOpen] = useState(false);

    useEffect(() => {
        if (!isPlaying) {
            setIsOpen(false);
            return;
        }
        const interval = setInterval(() => {
            setIsOpen((prev) => !prev);
        }, 2000);
        return () => clearInterval(interval);
    }, [isPlaying]);

    return (
        <div className="relative flex h-64 w-full items-center justify-center overflow-hidden rounded-2xl bg-white p-6 shadow-sm ring-1 ring-stone-200">
            {"text-stone-400 italic">/* Underlay Dashboard Mock */}
            <div className="grid grid-cols-2 gap-4 opacity-30">
                <div className="h-24 w-24 rounded-xl bg-stone-200" />
                <div className="h-24 w-24 rounded-xl bg-stone-200" />
            </div>

            <AnimatePresence>
                {isOpen && (
                    <div className="absolute inset-0 z-10 flex items-center justify-center">
                        {"text-stone-400 italic">/* Backdrop Fade */}
                        <motion.div
                            initial={{ opacity: 0 }}
                            animate={{ opacity: 1 }}
                            exit={{ opacity: 0 }}
                            className="absolute inset-0 bg-stone-900/20 backdrop-blur-sm"
                        />

                        {"text-stone-400 italic">/* Modal Scale In */}
                        <motion.div
                            initial={{ scale: 0.95, opacity: 0, y: 10 }}
                            animate={{ scale: 1, opacity: 1, y: 0 }}
                            exit={{ scale: 0.95, opacity: 0, y: 10 }}
                            transition={{ type: 'spring', stiffness: 400, damping: 25 }}
                            className="relative z-10 flex w-48 flex-col items-center gap-3 rounded-2xl bg-white p-6 shadow-xl ring-1 ring-stone-200"
                        >
                            <div className="flex h-10 w-10 items-center justify-center rounded-full bg-red-50 mb-2">
                                <div className="h-5 w-5 rounded-full bg-red-400" />
                            </div>
                            <div className="h-4 w-24 rounded bg-stone-800" />
                            <div className="h-3 w-32 rounded bg-stone-300" />
                        </motion.div>
                    </div>
                )}
            </AnimatePresence>
        </div>
    );
}