Back to Dictionary
Action Feedback
●○○Ready to Use
Recommended default

Fluid Password Strength Gauge

A smooth, interpolating bar that physically stretches and continuously shifts color from red (weak) to yellow (fair) to green (strong) as the user types.

Use

User registration

Avoid

Standard non-sensitive data inputs

Safer Alternative

No safer default listed.

Risk Level

Low risk

Live Demo

SecurityEnter password

What It Is

A smooth, interpolating bar that physically stretches and continuously shifts color from red (weak) to yellow (fair) to green (strong) as the user types.

When to Use

  • User registration
  • Password reset forms
  • Security setting pages

When NOT to Use

  • Standard non-sensitive data inputs

Configuration Tips

  • 01Use Framer Motion to animate the `width` and `backgroundColor` of a single div simultaneously.

You've Seen It In

Auth0GitHub Signup1Password

AI Implementation Prompts

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

Create a password strength indicator line that animates its width and color from red (20%) to yellow (50%) to green (100%) based on input character count.

Reference Implementation

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

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

export function PasswordStrengthGaugeDemo({ isPlaying = false }: { isPlaying?: boolean }) {
    const [password, setPassword] = useState("");

    useEffect(() => {
        if (!isPlaying) {
            setPassword("");
            return;
        }

        const typed = "Tr0ub4dor&3";
        let index = 0;

        const loop = setInterval(() => {
            if (index <= typed.length) {
                setPassword(typed.substring(0, index));
                index++;
            } else {
                clearInterval(loop);
                setTimeout(() => setPassword(""), 1000);
            }
        }, 200);

        const restartLoop = setInterval(() => {
            index = 0;
            setPassword("");
        }, 4000);

        return () => {
            clearInterval(loop);
            clearInterval(restartLoop);
        };
    }, [isPlaying]);

    "text-stone-400 italic">// Calculate strength based on length (simplified for demo)
    const strength = Math.min(100, (password.length / 10) * 100);

    "text-stone-400 italic">// Determine color
    const getColor = (str: number) => {
        if (str === 0) return "#e5e7eb"; "text-stone-400 italic">// stone-200
        if (str < 40) return "#ef4444"; "text-stone-400 italic">// red-500
        if (str < 80) return "#eab308"; "text-stone-400 italic">// yellow-500
        return "#10b981"; "text-stone-400 italic">// emerald-500
    };

    const getLabel = (str: number) => {
        if (str === 0) return "Enter password";
        if (str < 40) return "Weak";
        if (str < 80) return "Fair";
        return "Strong";
    };

    return (
        <div className="flex h-64 w-full items-center justify-center overflow-hidden rounded-2xl bg-white p-4 shadow-sm ring-1 ring-stone-200">
            <div className="w-full max-w-xs flex flex-col gap-3">
                <input
                    type="password"
                    value={password}
                    onChange={(e) => setPassword(e.target.value)}
                    placeholder="Enter password"
                    className="w-full rounded-lg border border-stone-200 bg-stone-50 px-4 py-3 outline-none focus:border-indigo-500 focus:bg-white transition-colors"
                />

                {"text-stone-400 italic">/* The Gauge */}
                <div className="flex flex-col gap-1.5 px-1">
                    <div className="h-1.5 w-full bg-stone-100 rounded-full overflow-hidden">
                        <motion.div
                            className="h-full rounded-full"
                            animate={{
                                width: `${strength}%`,
                                backgroundColor: getColor(strength)
                            }}
                            transition={{ type: "spring", stiffness: 200, damping: 20 }}
                        />
                    </div>
                    <div className="flex justify-between items-center text-xs">
                        <span className="text-stone-400 font-medium">Security</span>
                        <motion.span
                            key={getLabel(strength)}
                            initial={{ opacity: 0, y: 5 }}
                            animate={{ opacity: 1, y: 0 }}
                            className="font-bold uppercase tracking-wider"
                            style={{ color: strength === 0 ? "#9ca3af" : getColor(strength) }}
                        >
                            {getLabel(strength)}
                        </motion.span>
                    </div>
                </div>
            </div>
        </div>
    );
}