Back to Dictionary
Action Feedback
●●○Customize
Context dependent

Long Press Feedback

A visual indicator (like a filling ring or background) that shows the progress of a long-press action before it executes.

Use

Destructive actions (e.g., "Hold to delete")

Avoid

Standard navigation

Safer Alternative

No safer default listed.

Risk Level

Low risk

Live Demo

What It Is

A visual indicator (like a filling ring or background) that shows the progress of a long-press action before it executes.

When to Use

  • Destructive actions (e.g., "Hold to delete")
  • Recording audio/video
  • Revealing hidden secondary menus

When NOT to Use

  • Standard navigation
  • Primary positive actions where speed is important

Configuration Tips

  • 01Provide clear visual growth (like a radial progress bar or growing circle)
  • 02Set the required hold duration between 500ms and 1500ms

You've Seen It In

Instagram (recording)iOS Home ScreenTelegram

AI Implementation Prompts

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

Create a button that requires the user to hold it for 1 second. Show a ring filling up while they hold it.

Reference Implementation

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

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

export function LongPressFeedbackDemo({ isPlaying = false }: { isPlaying?: boolean }) {
    const [isPressing, setIsPressing] = useState(false);
    const controls = useAnimation();

    useEffect(() => {
        if (!isPlaying) {
            requestAnimationFrame(() => {
                try {
                    controls.stop();
                    controls.set({ scale: 0, opacity: 0 });
                } catch (e) { }
            });
            setIsPressing(false);
            return;
        }

        "text-stone-400 italic">// Simulate long press
        const simulatePress = async () => {
            setIsPressing(true);
            await controls.start({
                scale: 1,
                opacity: 0.15,
                transition: { duration: 1, ease: 'linear' }
            });
            "text-stone-400 italic">// Flash success upon completion
            await controls.start({ opacity: 0, transition: { duration: 0.2 } });
            controls.set({ scale: 0 });
            setIsPressing(false);
        };

        const interval = setInterval(simulatePress, 2500);
        simulatePress();

        return () => clearInterval(interval);
    }, [isPlaying, controls]);

    return (
        <div className="flex h-64 w-full items-center justify-center rounded-2xl bg-white p-6 shadow-sm ring-1 ring-stone-200">
            <button className="relative flex h-24 w-24 items-center justify-center overflow-hidden rounded-full border border-stone-200 bg-stone-50 text-stone-900 shadow-sm outline-none transition-colors hover:bg-stone-100">
                <motion.div
                    animate={controls}
                    initial={{ scale: 0, opacity: 0 }}
                    className="absolute inset-0 origin-center rounded-full bg-stone-900"
                />
                <span className="relative z-10 text-sm font-medium">Hold Me</span>
            </button>
        </div>
    );
}