SwiftUI Patterns

Password Strength Indicators

June 24, 2026
4 min read
Featured image for blog post: Password Strength Indicators

Visual password strength indicators help users create secure passwords. Here's how to build one.

Follow along with the code: iOS-Practice on GitHub

Strength Calculation

enum PasswordStrength {
    case none, weak, medium, strong

    var color: Color {
        switch self {
        case .none: return .gray
        case .weak: return .red
        case .medium: return .orange
        case .strong: return .green
        }
    }

    var label: String {
        switch self {
        case .none: return ""
        case .weak: return "Weak"
        case .medium: return "Medium"
        case .strong: return "Strong"
        }
    }
}

Strength Algorithm

var passwordStrength: PasswordStrength {
    if password.isEmpty { return .none }
    if password.count < 8 { return .weak }

    var score = 0
    if password.count >= 12 { score += 1 }
    if password.contains(where: { $0.isUppercase }) { score += 1 }
    if password.contains(where: { $0.isNumber }) { score += 1 }
    if password.contains(where: { "!@#$%^&*()".contains($0) }) { score += 1 }

    switch score {
    case 0...1: return .weak
    case 2: return .medium
    default: return .strong
    }
}

Visual Indicator

struct PasswordStrengthView: View {
    let strength: PasswordStrength

    var body: some View {
        HStack(spacing: 4) {
            ForEach(0..<3) { index in
                RoundedRectangle(cornerRadius: 2)
                    .fill(index < strengthLevel ? strength.color : Color.gray.opacity(0.3))
                    .frame(height: 4)
            }
            Text(strength.label)
                .font(.caption)
                .foregroundColor(strength.color)
        }
    }

    var strengthLevel: Int {
        switch strength {
        case .none: return 0
        case .weak: return 1
        case .medium: return 2
        case .strong: return 3
        }
    }
}

Integration

Section("Password") {
    SecureField("Password", text: $formModel.password)
        .textContentType(.newPassword)

    if let error = formModel.passwordError {
        Text(error)
            .font(.caption)
            .foregroundColor(.red)
    }

    PasswordStrengthView(strength: formModel.passwordStrength)

    SecureField("Confirm Password", text: $formModel.confirmPassword)

    if let error = formModel.confirmPasswordError {
        Text(error)
            .font(.caption)
            .foregroundColor(.red)
    }
}

Real-Time Updates

Because passwordStrength is a computed property on an ObservableObject, the indicator updates as the user types.

Customizing Criteria

Adjust the algorithm for your requirements:

var score = 0

// Length bonus
if password.count >= 12 { score += 1 }
if password.count >= 16 { score += 1 }

// Character variety
if password.contains(where: { $0.isUppercase }) { score += 1 }
if password.contains(where: { $0.isLowercase }) { score += 1 }
if password.contains(where: { $0.isNumber }) { score += 1 }
if password.contains(where: { "!@#$%^&*()_+-=[]{}|;:',.<>?".contains($0) }) { score += 1 }

// No common patterns
if !containsCommonPatterns(password) { score += 1 }

Alternative Visual Styles

Progress bar:

ProgressView(value: Double(strengthLevel) / 3.0)
    .tint(strength.color)

Checkmarks:

HStack {
    CheckItem("8+ characters", met: password.count >= 8)
    CheckItem("Uppercase", met: password.contains(where: \.isUppercase))
    CheckItem("Number", met: password.contains(where: \.isNumber))
}

Interview Tip

This demonstrates computed properties, enums with associated data, and reactive UI—all common SwiftUI patterns.

Originally published on pixelper.com

© 2026 Christopher Moore / Dead Pixel Studio

Let's work together

Professional discovery, design, and complete technical coverage for your ideas

Get in touch