Flutter - Password Field with Strength Validation Checker

This tutorial shows you how to create a password field in Flutter with a strength indicator bar that changes as the user types.

It's quite common for a password field to have a bar that indicates how strong the current password is. It can be useful to encourage the users to consider another password if the current one is not strong enough. Usually, there is a bar that shows how good the current value is and it's updated as the user types. Below is the example of how to create that interface in Flutter.

Create Password Strength Calculator

The first thing to do is determine the algorithm to calculate the strength of the inputted text. Below is the rule used in this tutorial. Of course you can change it with your own.

  • Empty: do not showing anything if the user hasn't typed
  • Weak: if the password is shorter than 6
  • Medium: if the password is shorter than 10
  • Strong: If the password is longer than or equal to 10, but doesn't include all recommended characters (lower case, upper case, number, symbol).
  • Very strong: If the password is longer than or equal to 10 and includes all recommended characters (lower case, upper case, number, symbol).

There are 5 levels of strength. We can create an enum for it using Dart's enhanced enum. The enum also contains the text to be displayed, the fractional value (how much it fills the bar), and the color to fill the bar.

  enum Strength {
    empty('', 0 / 4, Colors.transparent),
    weak('weak', 1 / 4, Colors.red),
    medium('medium', 2 / 4, Colors.yellow),
    strong('strong', 3 / 4, Colors.blue),
    veryStrong('very strong', 4 / 4, Colors.green),
    ;
  
    final String text;
    final double value;
    final Color color;
  
    const Strength(this.text, this.value, this.color);
  }

Based on the rule above, we can write the method below.

  class ExampleState extends State<Example> {
  
    Strength _calculatePasswordStrength(String value) {
      if (value.length < 6) {
        return Strength.weak;
      } else if (value.length < 10) {
        return Strength.medium;
      } else {
        final containsRecommendedChars = value.contains(RegExp(r'[A-Z]'))
            && value.contains(RegExp(r'[a-z]'))
            && value.contains(RegExp(r'[0-9]'))
            && value.contains(RegExp(r'[!@#$%^&*(),.?":{}|<>]'));
  
        if (!containsRecommendedChars) {
          return Strength.strong;
        } else {
          return Strength.veryStrong;
        }
      }
    }
  }

Since the strength may change when the text is updated, we also need to store the current strength. It can be stored in a state variable. Below is the state variable and a method that can update it based on the return of the _calculatePasswordStrength method.

  Strength _strength = Strength.empty;

    void _updatePasswordStrength(String value) {
    setState(() {
      _strength = _calculatePasswordStrength(value);
    });
  }

Create Text Field

Next, we need to create a text field for inputting the password. It's just a usual TextField or TextFormField where the obscuredText is set to true, so that the typed password is not visible. An important thing to add is a handler to update _strength value every time the text changes. It can be done by passing a callback as the onChanged argument.

  TextField(
    onChanged: (value) => _updatePasswordStrength(value),
    obscureText: true,
    decoration: const InputDecoration(
      border: OutlineInputBorder(),
      labelText: 'Password',
    ),
  )

Create Strength Indicator Bar

An easy way to create a strength indicator bar is by using the LinearProgressIndicator widget. The value argument has a range from 0 (no progress) to 1 (complete). It can be obtained from the current enum. The enum above also has a color property which can be passed as the color argument, so that we can show different colors based on the current strength.

  LinearProgressIndicator(
    minHeight: 20,
    value: _strength.value,
    backgroundColor: Colors.grey,
    color: _strength.color,
  )

In addition, you can also add a text that indicates the strength of the password.

  Text(_strength.text.isNotEmpty ? 'Your password is ${_strength.text}' : '')

Flutter - Password Field with Strength Validation Checker

Full Code

  import 'package:flutter/material.dart';
  
  enum Strength {
    empty('', 0 / 4, Colors.transparent),
    weak('weak', 1 / 4, Colors.red),
    medium('medium', 2 / 4, Colors.yellow),
    strong('strong', 3 / 4, Colors.blue),
    veryStrong('very strong', 4 / 4, Colors.green),
    ;
  
    final String text;
    final double value;
    final Color color;
  
    const Strength(this.text, this.value, this.color);
  }
  
  void main() => runApp(const MyApp());
  
  class MyApp extends StatelessWidget {
  
    const MyApp({Key? key}) : super(key: key);
  
    @override
    Widget build(BuildContext context) {
      return MaterialApp(
        title: 'Woolha.com Flutter Tutorial',
        home: Scaffold(
          appBar: AppBar(
            title: const Text('Woolha.com Flutter Tutorial'),
            backgroundColor: Colors.teal,
          ),
          body: const Example(),
        ),
      );
    }
  }
  
  class Example extends StatefulWidget {
    const Example({super.key});
  
    @override
    State<StatefulWidget> createState() {
      return ExampleState();
    }
  }
  
  class ExampleState extends State<Example> {
  
    Strength _strength = Strength.empty;
  
    void _updatePasswordStrength(String value) {
      setState(() {
        _strength = _calculatePasswordStrength(value);
      });
    }
  
    Strength _calculatePasswordStrength(String value) {
      if (value.length < 6) {
        return Strength.weak;
      } else if (value.length < 10) {
        return Strength.medium;
      } else {
        final containsRecommendedChars = value.contains(RegExp(r'[A-Z]'))
            && value.contains(RegExp(r'[a-z]'))
            && value.contains(RegExp(r'[0-9]'))
            && value.contains(RegExp(r'[!@#$%^&*(),.?":{}|<>]'));
  
        if (!containsRecommendedChars) {
          return Strength.strong;
        } else {
          return Strength.veryStrong;
        }
      }
    }
  
    @override
    Widget build(BuildContext context) {
      return Padding(
        padding: const EdgeInsets.all(10),
        child: Column(
          children: [
            TextField(
              onChanged: (value) => _updatePasswordStrength(value),
              obscureText: true,
              decoration: const InputDecoration(
                border: OutlineInputBorder(),
                labelText: 'Password',
              ),
            ),
            const SizedBox(
              height: 30,
            ),
            LinearProgressIndicator(
              minHeight: 20,
              value: _strength.value,
              backgroundColor: Colors.grey,
              color: _strength.color,
            ),
            const SizedBox(
              height: 10,
            ),
            Text(_strength.text.isNotEmpty ? 'Your password is ${_strength.text}' : '')
          ],
        ),
      );
    }
  }

Summary

That's how to add a password strength indicator in Flutter. You need to define the algorithm for calculating the strength of the inputted text. Then, create a text field that has a callback for re-calculating the strength every time the text changes. Finally, you can add a LinearProgressIndicator to show how strong the current password is.

You can also read about: