Password Generator

Generate strong, cryptographically random passwords with customizable length and character sets.

Security
100% Free
Runs in Browser

Preview

Source Code

Toggle the controls below the code to live-edit the initial state values.

password-generator.tsx
import { useState, useCallback } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Badge } from "@/components/ui/badge";
import { Copy, Check, RefreshCw } from "lucide-react";

const CHARS = {
    lower: "abcdefghijklmnopqrstuvwxyz",
    upper: "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
    numbers: "0123456789",
    symbols: "!@#$%^&*()_+-=[]{}|;:,.<>?",
};

function calcStrength(password: string): { label: string; color: string; score: number } {
    let score = 0;
    if (password.length >= 8) score++;
    if (password.length >= 12) score++;
    if (password.length >= 16) score++;
    if (/[a-z]/.test(password) && /[A-Z]/.test(password)) score++;
    if (/\d/.test(password)) score++;
    if (/[^a-zA-Z0-9]/.test(password)) score++;

    if (score <= 2) return { label: "Weak", color: "text-red-500", score };
    if (score <= 4) return { label: "Medium", color: "text-yellow-500", score };
    return { label: "Strong", color: "text-green-500", score };
}

export default function PasswordGenerator() {
    const [length, setLength] = useState(16);
    const [options, setOptions] = useState({
        lower: true,
        upper: true,
        numbers: true,
        symbols: true,
    });
    const [password, setPassword] = useState("");
    const [copied, setCopied] = useState(false);

    const generate = useCallback(() => {
        let pool = "";
        if (options.lower) pool += CHARS.lower;
        if (options.upper) pool += CHARS.upper;
        if (options.numbers) pool += CHARS.numbers;
        if (options.symbols) pool += CHARS.symbols;
        if (!pool) pool = CHARS.lower;

        const arr = new Uint32Array(length);
        crypto.getRandomValues(arr);
        const pw = Array.from(arr, (n) => pool[n % pool.length]).join("");
        setPassword(pw);
    }, [length, options]);

    const copyPw = async () => {
        await navigator.clipboard.writeText(password);
        setCopied(true);
        setTimeout(() => setCopied(false), 1500);
    };

    const strength = password ? calcStrength(password) : null;

    const toggleOption = (key: keyof typeof options) => {
        setOptions((o) => ({ ...o, [key]: !o[key] }));
    };

    return (
        <div className="space-y-4">
            <div className="flex flex-wrap items-center gap-3">
                <span className="text-sm text-muted-foreground">Length</span>
                <Input
                    type="number"
                    min={4}
                    max={128}
                    value={length}
                    onChange={(e) => setLength(Number(e.target.value) || 8)}
                    className="w-20"
                />
                <input
                    type="range"
                    min={4}
                    max={128}
                    value={length}
                    onChange={(e) => setLength(Number(e.target.value))}
                    className="flex-1 min-w-[100px]"
                />
            </div>
            <div className="flex flex-wrap gap-2">
                {(Object.keys(options) as (keyof typeof options)[]).map((key) => (
                    <Button
                        key={key}
                        variant={options[key] ? "default" : "outline"}
                        size="sm"
                        onClick={() => toggleOption(key)}
                    >
                        {key === "lower" ? "a-z" : key === "upper" ? "A-Z" : key === "numbers" ? "0-9" : "!@#"}
                    </Button>
                ))}
            </div>
            <Button onClick={generate} className="w-full">
                <RefreshCw className="mr-2 h-4 w-4" />
                Generate Password
            </Button>
            {password && (
                <div className="relative rounded-lg border bg-muted/50 p-4">
                    <code className="text-lg font-mono break-all">{password}</code>
                    <Button
                        variant="ghost"
                        size="icon"
                        className="absolute top-2 right-2"
                        onClick={copyPw}
                    >
                        {copied ? <Check className="h-4 w-4" /> : <Copy className="h-4 w-4" />}
                    </Button>
                    {strength && (
                        <div className="mt-3 flex items-center gap-2">
                            <div className="flex-1 h-2 rounded-full bg-muted overflow-hidden">
                                <div
                                    className="h-full rounded-full transition-all"
                                    style={{
                                        width: `${(strength.score / 6) * 100}%`,
                                        backgroundColor: strength.label === "Weak" ? "#ef4444" : strength.label === "Medium" ? "#eab308" : "#22c55e",
                                    }}
                                />
                            </div>
                            <span className={`text-sm font-medium ${strength.color}`}>
                                {strength.label}
                            </span>
                        </div>
                    )}
                </div>
            )}
        </div>
    );
}
Props Playground
2 props
16

Required Libraries

Install the external dependencies used by this tool.

bun add lucide-react react

Shadcn UI Setup

Add the required Shadcn UI primitives to your project.

bun x --bun shadcn@latest add badge button input

Shadcn UI Components

The following primitives are required in your @/components/ui directory.

Component Import Path
badge @/components/ui/badge
button @/components/ui/button
input @/components/ui/input

Imports

All import statements used in this tool.

Source Exports
react useState, useCallback
@/components/ui/button Button
@/components/ui/input Input
@/components/ui/badge Badge
lucide-react Copy, Check, RefreshCw

State Management

React state variables managed within this tool.

Variable Initial Value
length 16
options { lower: true, upper: true, numbers: true, symbols: true, }
password ""
copied false

Variables & Constants

Constants and computed values defined in this tool.

Name Value
arr new Uint32Array(length)
pw Array.from(arr, (n) => pool[n % pool.length]).join("")
strength password ? calcStrength(password) : null

Functional Logic

Internal functions that handle the tool's core logic.

Function Parameters Async
calcStrength() password: string No
copyPw() None
Yes
toggleOption() key: keyof typeof options No

External Resources

Documentation, tutorials, and package details for libraries used in this tool.