Componentform1.25 KB gzipZero dependencies

Password Strength

Segmented security verification meter with animated strength bars and criteria checklist.

Preview

Live Preview
CURRENT KEY:ticket
SECURITY METERREVOKED / WEAK
✓MIN 8 CHARACTERS
✓UPPERCASE & LOWERCASE
✓NUMERIC DIGIT (0-9)
✓SPECIAL SYMBOL (#$@!)

Installation

Tokens guide →

Add to your project via CLI (zero dependencies, code you own):

npx bigbullui add password-strength

Or install the full npm package:

npm install bigbullui
import { PasswordStrength } from "@/components/ui/password-strength";

<PasswordStrength value="TicketSecret!2026" />

Usage guidance

Use Password Strength when a ticket stub surface needs Segmented security verification meter with animated strength bars and criteria checklist. Keep props minimal and prefer composition with sibling stubs.

Avoid Password Strength for long form flows or dense data grids where a dedicated layout block fits better.

Source code

password-strength.tsx

Zero dependencies (only React + utils). Copy and paste directly into your project:

"use client";

import * as React from "react";
import { cn } from "./lib/utils";

export interface PasswordStrengthProps extends React.HTMLAttributes<HTMLDivElement> {
  value?: string;
  className?: string;
  showCriteria?: boolean;
}

interface Criteria {
  label: string;
  met: boolean;
}

export function PasswordStrength({
  value = "",
  className,
  showCriteria = true,
  ...props
}: PasswordStrengthProps) {
  const criteria: Criteria[] = React.useMemo(() => [
    { label: "MIN 8 CHARACTERS", met: value.length >= 8 },
    { label: "UPPERCASE & LOWERCASE", met: /[A-Z]/.test(value) && /[a-z]/.test(value) },
    { label: "NUMERIC DIGIT (0-9)", met: /[0-9]/.test(value) },
    { label: "SPECIAL SYMBOL (#$@!)", met: /[^A-Za-z0-9]/.test(value) },
  ], [value]);

  const metCount = criteria.filter((c) => c.met).length;

  const strengthLevel = React.useMemo(() => {
    if (value.length === 0) return { label: "NO TICKET KEY", color: "bg-muted", width: "0%" };
    if (metCount <= 1) return { label: "REVOKED / WEAK", color: "bg-destructive", width: "25%" };
    if (metCount === 2) return { label: "STANDBY / FAIR", color: "bg-warning", width: "50%" };
    if (metCount === 3) return { label: "VALID / GOOD", color: "bg-warning", width: "75%" };
    return { label: "SECURE / ADMITTED", color: "bg-success", width: "100%" };
  }, [value, metCount]);

  return (
    <div className={cn("space-y-3 font-mono", className)} {...props}>
      {/* Header Info */}
      <div className="flex items-center justify-between text-xs">
        <span className="text-[10px] font-bold uppercase tracking-[0.2em] text-muted-foreground">
          SECURITY METER
        </span>
        <span className="font-bold text-foreground transition-colors duration-300">
          {strengthLevel.label}
        </span>
      </div>

      {/* Segmented Meter Bar */}
      <div className="grid grid-cols-4 gap-1.5 p-1 rounded-md border border-border bg-secondary/50">
        {[0, 1, 2, 3].map((step) => {
          const isActive = step < metCount;
          return (
            <div
              key={step}
              className={cn(
                "h-2 rounded-sm transition-all duration-300",
                isActive ? strengthLevel.color : "bg-muted opacity-40",
                isActive && "shadow-xs"
              )}
            />
          );
        })}
      </div>

      {/* Criteria Checklist */}
      {showCriteria && (
        <div className="space-y-1.5 pt-1 border-t border-dashed border-border/80 text-[11px]">
          {criteria.map((c, i) => (
            <div
              key={i}
              className={cn(
                "flex items-center gap-2 transition-colors duration-200",
                c.met ? "text-foreground font-medium" : "text-muted-foreground/70"
              )}
            >
              <span
                className={cn(
                  "size-4 rounded-sm border flex items-center justify-center text-[10px] transition-all",
                  c.met
                    ? "border-accent bg-accent text-accent-foreground font-bold scale-110"
                    : "border-border bg-card text-transparent"
                )}
              >
                ✓
              </span>
              <span>{c.label}</span>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

Props

PropTypeDescription
value?string
className?string
showCriteria?boolean