← Back to all tutorials

How to create a password strength meter with Tailwind CSS and Alpine JS

alpine-password-strength-meter
Published and written on Aug 30 2024 by Michael Andreuzza

Hello everyone! Let’s create a password strength meter using Alpine JS and Tailwind CSS. This tutorial will show you how to create a password strength meter that displays the strength of a password based on the number of characters, uppercase letters, lowercase letters, and special characters.

Why password strength meter?

Well, password strength meters are a great way to ensure that users are creating strong passwords. We all know that passwords are one of the most commonly used online security measures, and it’s essential to create strong passwords to protect your accounts and personal information.

Let’s write the markup

Let’s start by writing the markup for our password strength meter, we will start from the state variables and then move on to the markup for the password input and the password strength meter.

The Alpine JS data object is where we’ll define the properties and methods that will be used in our component. In this case, we’ll create a password property to store the user’s password, a strength property to store the strength of the password, a showPassword property to determine whether the password input is visible or not, and a checkStrength method to check the strength of the password.

The state variables

  • password: This is a string property that will store the user’s password.
  • strength: This is a string property that will store the strength of the password.
  • showPassword: This is a boolean property that will determine whether the password input is visible or not.
   password: '',
    strength: '',
    showPassword: false,

Resetting the strength if password is empty

  • if (password.length === 0): This condition checks if the password is empty.
  • this.strength = '': If the password is empty, we set the strength to an empty string.
  • return;: This is a return statement that exits the function early.
 if (password.length === 0) {
     this.strength = '';
     return;
 }

Initializing the strength to weak by default

  • this.strength = 'weak';: This sets the strength to ‘weak’ by default.
this.strength = 'weak';

Defining conditions for different levels of password strength

We’ll define conditions for different levels of password strength using regular expressions. The conditions will check if the password contains lowercase letters, uppercase letters, numbers, and special characters.

  • const hasLowerCase = /[a-z]/.test(password);: This regular expression checks if the password contains lowercase letters.
  • const hasUpperCase = /[A-Z]/.test(password);: This regular expression checks if the password contains uppercase letters.
  • const hasNumber = /\d/.test(password);: This regular expression checks if the password contains numbers.
  • const hasSpecialChar = /[!@#$%^&*(),.?':{}|<>]/.test(password);: This regular expression checks if the password contains special characters.
// Define conditions for different levels of password strength
const hasLowerCase = /[a-z]/.test(password);
const hasUpperCase = /[A-Z]/.test(password);
const hasNumber = /\d/.test(password);
const hasSpecialChar = /[!@#$%^&*(),.?':{}|<>]/.test(password);

Counting the number of passed checks

We’ll count the number of passed checks using the filter method. The filter method returns a new array with all elements that pass the test implemented by the provided function.

  • const passedChecks = [hasLowerCase, hasUpperCase, hasNumber, hasSpecialChar].filter(Boolean).length;: This line of code counts the number of passed checks. We pass the Boolean function as an argument to the filter method, which returns a new array with all elements that pass the test implemented by the provided function.
 // Count the number of passed checks
 const passedChecks = [hasLowerCase, hasUpperCase, hasNumber, hasSpecialChar].filter(Boolean).length;

Updating strength based on conditions

We’ll update the strength based on the conditions using an if statement. The if statement checks if the password length is greater than or equal to 8, and if the number of passed checks is greater than or equal to 3.

  • if (password.length >= 8): This condition checks if the password length is greater than or equal to 8.
  • if (passedChecks === 4 || password.length >= 12): This condition checks if the number of passed checks is 4 or if the password length is greater than or equal to 12.
  • this.strength = 'very strong';: If the password length is greater than or equal to 12 and the number of passed checks is 4, we set the strength to ‘very strong’.
  • else if (passedChecks >= 3): This condition checks if the number of passed checks is greater than or equal to 3.
  • this.strength = 'strong';: If the number of passed checks is greater than or equal to 3, we set the strength to ‘strong’.
  • else if (passedChecks >= 2): This condition checks if the number of passed checks is greater than or equal to 2.
  • this.strength = 'medium';: If the number of passed checks is greater than or equal to 2, we set the strength to ‘medium’.
// Update strength based on conditions
if (password.length >= 8) {
    if (passedChecks === 4 || password.length >= 12) {
        this.strength = 'very strong';
    } else if (passedChecks >= 3) {
        this.strength = 'strong';
    } else if (passedChecks >= 2) {
        this.strength = 'medium';
    }
}

The full Alpine JS data object

Here is the full Alpine JS data object for our password strength meter:

x-data="{
    password: '',
    strength: '',
    showPassword: false,
    checkStrength() {
      const password = this.password;

      // Reset the strength if password is empty
      if (password.length === 0) {
        this.strength = '';
        return;
      }

      // Initialize the strength to weak by default
      this.strength = 'weak';

      // Define conditions for different levels of password strength
      const hasLowerCase = /[a-z]/.test(password);
      const hasUpperCase = /[A-Z]/.test(password);
      const hasNumber = /\d/.test(password);
      const hasSpecialChar = /[!@#$%^&*(),.?':{}|<>]/.test(password);

      // Count the number of passed checks
      const passedChecks = [hasLowerCase, hasUpperCase, hasNumber, hasSpecialChar].filter(Boolean).length;

      // Update strength based on conditions
      if (password.length >= 8) {
        if (passedChecks === 4 || password.length >= 12) {
          this.strength = 'very strong';
        } else if (passedChecks >= 3) {
          this.strength = 'strong';
        } else if (passedChecks >= 2) {
          this.strength = 'medium';
        }
      }
    }
}"

Let’s move to the input

Now that we have the data object, let’s move on to the input.

The input

Classes are removed for brecity, but you can get the full code on the GitHub repository.

Attributes

  • id="password": Assigns a unique ID to the input.
  • :type="showPassword ? 'text' : 'password'": This attribute sets the type of the input based on the value of the showPassword property.
  • x-model="password": This attribute binds the password property to the input.
  • @input="checkStrength()": This attribute calls the checkStrength method when the input value changes.
<input
id="password"
:type="showPassword ? 'text' : 'password'"
x-model="password"
@input="checkStrength()"
/>

Toggle password visibility

The wrapper for the password input also includes a button that toggles the visibility of the password input.

  • @click="showPassword = !showPassword": This attribute calls the showPassword property when the button is clicked.
  • type="button": This attribute sets the button type to button.

The icons The button contains two span elements, one for the password visibility icon and one for the password strength icon.

  • x-show="!showPassword": This attribute hides the password visibility icon when the password input is visible.
  • x-show="showPassword": This attribute hides the password strength icon when the password input is visible.
<button
@click="showPassword = !showPassword"
type="button">
  <span x-show="!showPassword">
    <!-- SVG goes here -->
  </span>
  <span x-show="showPassword">
    <!-- SVG goes here -->
  </span>
</button>

The password strength meter

The password strength meter is a simple progress bar that displays the strength of the password based on the number of characters, uppercase letters, lowercase letters, and special characters.

  • w-1/4 bg-red-500: This class sets the width to 1/4 of the container and the background color to red.
  • w-1/2 bg-yellow-500: This class sets the width to 1/2 of the container and the background color to yellow.
  • w-3/4 bg-green-500: This class sets the width to 3/4 of the container and the background color to green.
  • w-full bg-blue-500: This class sets the width to 100% of the container and the background color to blue.
<div
:class="{
     'w-1/4 bg-red-500': strength === 'weak',
     'w-1/2 bg-yellow-500': strength === 'medium',
     'w-3/4 bg-green-500': strength === 'strong',
     'w-full bg-blue-500': strength === 'very strong'
   }">
</div>

Representing the strength of the password with text and color

The password strength meter also includes a text element that displays the strength of the password. The text element uses the x-text directive to bind the strength property to the text content and the :class directive to apply different classes based on the strength of the password.

  • text-red-500: This class sets the text color to red.
  • text-yellow-500: This class sets the text color to yellow.
  • text-green-500: This class sets the text color to green.
  • text-blue-500: This class sets the text color to blue.
<p
:class="{
    'text-red-500': strength === 'weak',
    'text-yellow-500': strength === 'medium',
    'text-green-500': strength === 'strong',
    'text-blue-500': strength === 'very strong'
  }">
Password strength:
<span x-text="strength"></span>
</p>

The full markup

Here is the full markup for the password strength meter. Note that irrelevant classes are removed for brevity and you can find them on repo.

 <div x-data="{
    password: '',
    strength: '',
    showPassword: false,
    checkStrength() {
      const password = this.password;

      // Reset the strength if password is empty
      if (password.length === 0) {
        this.strength = '';
        return;
      }

      // Initialize the strength to weak by default
      this.strength = 'weak';

      // Define conditions for different levels of password strength
      const hasLowerCase = /[a-z]/.test(password);
      const hasUpperCase = /[A-Z]/.test(password);
      const hasNumber = /\d/.test(password);
      const hasSpecialChar = /[!@#$%^&*(),.?':{}|<>]/.test(password);

      // Count the number of passed checks
      const passedChecks = [hasLowerCase, hasUpperCase, hasNumber, hasSpecialChar].filter(Boolean).length;

      // Update strength based on conditions
      if (password.length >= 8) {
        if (passedChecks === 4 || password.length >= 12) {
          this.strength = 'very strong';
        } else if (passedChecks >= 3) {
          this.strength = 'strong';
        } else if (passedChecks >= 2) {
          this.strength = 'medium';
        }
      }
    }
}" class="space-y-4 max-w-lg mt-12 border-t pt-6 mx-auto w-full">
   <!-- Password Input -->
   <div>
     <label for="password" class="sr-only">Password</label>
     <div class="relative">
       <input id="password" :type="showPassword ? 'text' : 'password'" x-model="password" @input="checkStrength()"/>
       <button @click="showPassword = !showPassword" type="button" class="absolute inset-y-0 right-0 flex items-center pr-3">
         <span x-show="!showPassword">
           <!-- SVG goes here -->
         </span>
         <span x-show="showPassword" >
           <!-- SVG goes here -->
         </span>
       </button>
     </div>
   </div>
   <!-- Password Strength Meter -->
   <div>
     <div class="h-full transition-all duration-300 ease-out" :class="{
      'w-1/4 bg-red-500': strength === 'weak',
      'w-1/2 bg-yellow-500': strength === 'medium',
      'w-3/4 bg-green-500': strength === 'strong',
      'w-full bg-blue-500': strength === 'very strong'
    }"></div>
   </div>
   <!-- Password Strength Text -->
   <p :class="{
    'text-red-500': strength === 'weak',
    'text-yellow-500': strength === 'medium',
    'text-green-500': strength === 'strong',
    'text-blue-500': strength === 'very strong'
  }"> Password strength: <span x-text="strength"></span>
   </p>
 </div>

Conlcusion

In this tutorial, we learned how to create a password strength meter using Alpine JS and Tailwind CSS, and how to use Alpine JS directives to conditionally display the content of the password strength meter based on the strength of the password.

I hope you found this tutorial helpful and have a great day!

/Michael Andreuzza

Did you like this tutorial? Please share it with your friends!

Get lifetime access to every theme available today for $199 $139 and own them forever. Plus, new themes, lifetime updates, use on unlimited projects and enjoy lifetime support.

— No subscription required!