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

Fade Transition

Choose fade when the best motion is the one users barely notice.

Use

Simple state changes where spatial direction is not meaningful.

Avoid

Avoid when users need to understand where an item moved from or where the next view came from.

Safer Alternative

Blur Fade-in

Risk Level

Use carefully

Timing

Use 120-220ms for interface state changes and up to 300ms for larger view swaps.

Easing

Ease-out for entering content; ease-in for exits; crossfades should stay subtle.

Risk

overdesigned

Live Demo

Content for Overview

What It Is

A smooth opacity transition between two states, pages, or components to prevent jarring instant visual changes.

Decision Guidance

Choose fade when the best motion is the one users barely notice.

Best For

Simple state changes where spatial direction is not meaningful.

Avoid When

Avoid when users need to understand where an item moved from or where the next view came from.

Timing

Use 120-220ms for interface state changes and up to 300ms for larger view swaps.

Easing

Ease-out for entering content; ease-in for exits; crossfades should stay subtle.

Risk Tags

overdesigned

When to Use

  • Navigating between tabs
  • Opening/closing simple modals
  • Revealing deferred content

When NOT to Use

  • High-energy interactions that need spatial awareness (use slides instead)

Configuration Tips

  • 01Keep it short: 150ms-200ms is standard for UI fades

You've Seen It In

AppleVercel

AI Implementation Prompts

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

Add a fade transition when switching between these tabs.

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 FadeTransitionDemo({ isPlaying = false }: { isPlaying?: boolean }) {
    const [activeTab, setActiveTab] = useState(0);

    useEffect(() => {
        if (isPlaying) {
            const timer = setInterval(() => {
                setActiveTab((prev) => (prev === 0 ? 1 : 0));
            }, 1500);
            return () => clearInterval(timer);
        }
    }, [isPlaying]);

    return (
        <div className="flex w-64 flex-col gap-4 rounded-2xl bg-white p-4 shadow-sm ring-1 ring-stone-200">
            <div className="flex gap-2 rounded-xl bg-stone-100 p-1">
                {['Overview', 'Settings'].map((tab, i) => (
                    <button
                        key={tab}
                        onClick={() => setActiveTab(i)}
                        className={`relative flex-1 rounded-lg px-3 py-1.5 text-xs font-medium transition-colors ${activeTab === i ? 'text-stone-900' : 'text-stone-500 hover:text-stone-700'
                            }`}
                    >
                        {activeTab === i && (
                            <motion.div
                                layoutId="activeTabIndicator"
                                className="absolute inset-0 rounded-lg bg-white shadow-sm ring-1 ring-stone-200/50"
                                transition={{ type: 'spring', stiffness: 400, damping: 30 }}
                            />
                        )}
                        <span className="relative z-10">{tab}</span>
                    </button>
                ))}
            </div>
            <div className="relative h-20 overflow-hidden">
                <AnimatePresence mode="wait">
                    <motion.div
                        key={activeTab}
                        initial={{ opacity: 0 }}
                        animate={{ opacity: 1 }}
                        exit={{ opacity: 0 }}
                        transition={{ duration: 0.2 }}
                        className="flex h-full items-center justify-center rounded-xl border border-dashed border-stone-200 bg-stone-50"
                    >
                        <span className="text-xs text-stone-400">Content for {activeTab === 0 ? 'Overview' : 'Settings'}</span>
                    </motion.div>
                </AnimatePresence>
            </div>
        </div>
    );
}