How to build a password strength meter with angular and material design

Anthony Nahas
@angular-material-extensions
7 min readJul 20, 2018

--

Photo by Matthew Brodeur on Unsplash

Motivation

Few month ago, I developed an UI library with angular and material design powered by angularfire2 in order to allow users’authentication with firebase projects. The library is called ngx-auth-firebaseui. Via this library, the users are able to create new accounts and sign up to any firebase project by providing a name, email and password. The filled data of the user will be validated on the server side by firebase. However, I noticed an extra client side validation would be awesome. The name and email could be easy validated with angular form controllers and validation regex e.g: see here. The most exciting part to validate was the password! Password’s validation and strength are some common use in an angular web app. For that reason, I create a new library and enhanced the angular material extensions projects named @angular-material-extensions/password-strength (previously ngx-material-password-strength) and is available here on npm for production.

If you are not interesting on how to build that extension, just skip the next sections and do the following:

  • Make sure that you have already installed the peer dependencies
npm i @angular/cdk @angular/material @angular/animations @angular/forms
npm install --save @angular-material-extensions/password-strength
  • Import the main module
import { MatPasswordStrengthModule } from '@angular-material-extensions/password-strength';
@NgModule({declarations: [AppComponent, ...],imports: [MatPasswordStrengthModule.forRoot(), ...],bootstrap: [AppComponent]})export class AppModule {}
  • Use the component in your template via mat-password-strength
<div><mat-form-field appearance="outline" style="width: 100%" [color]="passwordComponent.color"><mat-label>Password</mat-label><input matInput #password [type]="inputType" required placeholder="Password"><mat-hint align="end" aria-live="polite">{{password.value.length}} / 25</mat-hint></mat-form-field><!-- THE PASSWORD STRENGTH COMPONENT --><mat-password-strength #passwordComponent(onStrengthChanged)="onStrengthChanged($event)"[password]="password.value"></mat-password-strength>

What are we gonna build ? The following angular material extension →

The password strength meter is a progress bar component imported from the angular material module. We need to develop a mechanism for that progress bar in order to calculate the strength of a provided password (via an html input element)

Install the peer dependencies

Run the following command in your favorite terminal to install the peer dependencies:

npm i @angular/cdk @angular/material @angular/animations @angular/forms
  • cdk and material: to use the progress bar component
  • animations: to allow animations for the progress bar via the animation web api
  • forms: to validate and calculate the password’s strength

Import the required modules

In order to use the above installed packages, we need to import their main modules:

import {BrowserModule} from '@angular/platform-browser';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {FormsModule} from '@angular/forms';
import {MatProgressBarModule} from '@angular/material';
@NgModule({
declarations: [AppComponent, ...],
imports: [
BrowserModule.withServerTransition({appId: '@angular-material- extensions/password-strength-demo-id'}),
BrowserAnimationsModule,
FormsModule,
MatProgressBarModule, ...],
bootstrap: [AppComponent]
})
export class AppModule {
}

Add a material theme

please check the official documentation if you have not an angular material project based: https://material.angular.io/guide/getting-started#step-4-include-a-theme

  • paste the following in your style.css to include a theme:
@import '~@angular/material/theming';
// Plus imports for other components in your app.

// Include the common styles for Angular Material. We include this here so that you only
// have to load a single css file for Angular Material in your app.
// Be sure that you only ever include this mixin once!
@include
mat-core();

// Define the palettes for your theme using the Material Design palettes available in palette.scss
// (imported above). For each palette, you can optionally specify a default, lighter, and darker
// hue.
$candy-app-primary: mat-palette($mat-green);
$candy-app-accent: mat-palette($mat-deep-purple, A200, A100, A400);

// The warn palette is optional (defaults to red).
$candy-app-warn: mat-palette($mat-red);

// Create the theme object (a Sass map containing all of the palettes).
$candy-app-theme: mat-light-theme($candy-app-primary, $candy-app-accent, $candy-app-warn);

// Include theme styles for core and each component used in your app.
// Alternatively, you can import and @include the theme mixins for each component
// that you are using.
@include
angular-material-theme($candy-app-theme);

Generate a new component

ng generate component [name] # e.g: name = MatPasswordStrength

Write the view with html and the logic in typescript

The view is like I’ve said before, it’s just a progress bar from angular material.

We are using the above code to manipulate the progress bar to indicate the password’s strength.

In the following section, I will explain the typescript part from the top to the bottom briefly.

Enums

  • Colors: this represent actually the state of the password’s strength. That can vary between warn (when the provided password is not strong enough), accent (when the password is ok) and primary (when the password is strong)
  • Criteria: those are some helpful option to define when a a password is strong enough or not

Input

  • password: the provided password to be processed as string
  • validators: an array of criteria (you can customize your definition of a secure password like picking only 2 of 5 criteria)
  • externalError: a trigger to change the state of the password strength if an external error occurs

Output

  • onStrengthChanged: and event emitter that will be fired every time the state of the password strength changes (number between 0 and 100 in percentage)

How it works?

For every criteria, we test the password against a regular expression.

this.criteriaMap.set(Criteria.at_least_eight_chars, RegExp(/^.{8,63}$/));this.criteriaMap.set(Criteria.at_least_one_lower_case_char, RegExp(/^(?=.*?[a-z])/));this.criteriaMap.set(Criteria.at_least_one_upper_case_char, RegExp(/^(?=.*?[A-Z])/));this.criteriaMap.set(Criteria.at_least_one_digit_char, RegExp(/^(?=.*?[0-9])/));this.criteriaMap.set(Criteria.at_least_one_special_char, RegExp(/^(?=.*?[" !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~"])/));

Every time the password changes, the strength will be calculated and emitted:

ngOnChanges(changes: SimpleChanges): void {
if (changes.externalError && changes.externalError.firstChange) {
this._color = Colors.primary;
return;
}
if (changes.externalError && changes.externalError.currentValue) {
this._color = Colors.warn;
return;
}
this.password && this.password.length > 0 ?
this.calculatePasswordStrength() : this.reset();
}
// -----------------calculatePasswordStrength() {
const requirements: Array<boolean> = [];
const unit = 100 / 5;

requirements.push(
this._containAtLeastEightChars(),
this._containAtLeastOneLowerCaseLetter(),
this._containAtLeastOneUpperCaseLetter(),
this._containAtLeastOneDigit(),
this._containAtLeastOneSpecialChar());

this._strength = requirements.filter(v => v).length * unit;
this.onStrengthChanged.emit(this.strength);
}

After that, the value of the _strength property will be used to pick the right color for the component (the progress bar):

get strength(): number {
return this._strength ? this._strength : 0;
}

get color(): string {

if (this._strength <= 20) {
return Colors.warn;
} else if (this._strength <= 80) {
return Colors.accent;
} else {
return Colors.primary;
}
}

And here we go

Now you can use the component in your template like below:

<div>

<!--password input filed-->
<mat-form-field appearance="outline" style="width: 100%" [color]="passwordComponent.color">
<mat-label>Password</mat-label>
<input matInput #password
[type]=
"inputType"
required
placeholder=
"Password">
<mat-hint align="end" aria-live="polite">
{{password.value.length}} / 25
</mat-hint>
</mat-form-field>

<!--@angular-material-extensions/password-strength's main component-->
<mat-password-strength #passwordComponent
(onStrengthChanged)=
"onStrengthChanged($event)"
[password]="password.value">
</mat-password-strength>

</div>

If you prefer to use the password with a form, please consider to use the following code:

<!--password input filed-->
<mat-form-field appearance="outline" style="width: 100%">
<mat-label>Password</mat-label>
<input matInput #passwordWithValidation
[type]=
"inputType"
required
[formControl]=
"passwordComponentWithValidation.passwordFormControl"
placeholder="Password">

<!--password hint-->
<mat-hint align="end" aria-live="polite">
{{passwordWithValidation.value.length}} / 25
</mat-hint>

<!--password error msgs-->
<mat-error *ngIf="passwordComponentWithValidation.passwordFormControl.hasError('required')">
Password is required
</mat-error>
<mat-error *ngIf="passwordComponentWithValidation.passwordFormControl.hasError('pattern')">
Password is not valid
</mat-error>

</mat-form-field>

<!--@angular-material-extensions/password-strength's main component-->
<mat-password-strength #passwordComponentWithValidation
(onStrengthChanged)=
"onStrengthChanged($event)"
[password]="passwordWithValidation.value">
</mat-password-strength>

Demo

An demo app of the above created component can be found here https://angular-material-extensions.github.io/password-strength/

Documentation — API

https://angular-material-extensions.github.io/password-strength/doc/index.html

Summary

Today, we created an angular UI component to indicate how secure is a provided password with angular and material design. We didn’t create the UI from scratch but instead we used an already well done implemented component from the material2 project. Afterward, we developed the mechanism of the password strength in typescript and demonstrated that regular expressions are really awesome!

If you like this project, please support angular-material-extensions/password-strength by starring it here on github and sharing it with your friends.

Other angular material extensions:

Contribution

Would you like to join the team ? Contributions are welcome! Please feel free to contact us at support@angular-material-extensions.io

Author

Anthony Nahas founder of nahaus.de fullstack software developer experienced in: #Angular #NodeJS #SSR #MongoDB #Android #Google #Firebase #Docker #Dagger2 #Cordova #Ionic #WEB #APP #PWA

Github: https://github.com/AnthonyNahas

Twitter: https://twitter.com/ngAnthonyy

Web: https://anahas.de

My Property Management SaaS: https://nahaus.de

--

--

Anthony Nahas
@angular-material-extensions

Founder of Nahaus.de and Freelancer Software Developer sticking with the future and (#NodeJS #Angular #Google #Firebase #Ionic )