Dynamic Tooltip with Angular Pipe

Most of the time we have a requirement to transform our data into a different style or format from what we received from API services.

✋ A pipe takes in data as input and transforms it into a desired output.

Angular provides many Built-In Pipes as well as we can also create custom pipes as per our requirements.

 import { Pipe, PipeTransform } from '@angular/core'; 

In this Blog we will learn use of pipes with Tool tip.

Why need to implement a tooltip with Pipe ❓

Simple Message in Tooltip

If we have to apply a simple message in the tooltip like ‘Name is required’, so we can directly append the tooltip in HTML with a form control.

Conditional Tooltip

Sometimes we have to display tooltips with various checks. Examples of User name fields:

  1. Show the tooltip If the Field is blank
  2. If field’s value is less than 6 – show the tooltip message for length.
  3. If the username is found duplicate show a tooltip message for that.

▶️ If we do this in HTML, it will have various if else conditions checks.

▶️ We can call a method from the class file where we can put all cases and can return messages from there.

  TS File ▶
      getTooltip(): string {
        const field = this.form.controls.userName;
        // put our cases
        return message;

      HTML ▶
      <input type="text" formControlName = "userName" [tooltip] = "getTooltip()" />

In the above method, the problem is for each change detection this method will be called and that impacts page performance. So to overcome we can use pure pipes. Pure Pipes only execute when that particular field value is changed.

Let’s start coding :

tooltip with angular pipe

HTML template

<div class="card m-3">
  <h5 class="card-header">Implementation of Tooltip using Pipe</h5>
  <div class="card-body">
      <form [formGroup]="registerForm" (ngSubmit)="onSubmit()">
          <div class="form-row">
              <div class="form-group col">
                  <label>First Name</label>
                  <input type="text" formControlName="firstName" class="form-control" required
                   [ngClass]="{ 'is-invalid': submitted && f.firstName.errors }" 
                     [title] ="f.firstName.errors | regTooltip : 'firstName'" />
              <div class="form-group col">
                <input type="text" formControlName="email" class="form-control"  required
                [ngClass]="{ 'is-invalid': submitted && f.email.errors }" 
                [title] ="registerForm.controls.email.errors | regTooltip : 'email'"  />
          <div class="form-group">
          <div class="form-row">
              <div class="form-group col">
                  <input type="password" formControlName="password" class="form-control" 
                  [ngClass]="{ 'is-invalid': submitted && f.password.errors }"
                  [title] ="f.password.errors | regTooltip : 'password'" />
              <div class="form-group col">
                  <label>Confirm Password</label>
                  <input type="password" formControlName="confirmPassword" class="form-control" [ngClass]="{ 'is-invalid': submitted && f.confirmPassword.errors }" />
                  <div *ngIf="submitted && f.confirmPassword.errors" class="invalid-feedback">
                      <div *ngIf="f.confirmPassword.errors.required">Confirm Password is required</div>
                      <div *ngIf="f.confirmPassword.errors.mustMatch">Passwords must match</div>
          <div class="form-group form-check">
              <input type="checkbox" formControlName="acceptTerms" id="acceptTerms" class="form-check-input" [ngClass]="{ 'is-invalid': submitted && f.acceptTerms.errors }" />
              <label for="acceptTerms" class="form-check-label">Accept Terms & Conditions</label>
              <div *ngIf="submitted && f.acceptTerms.errors" class="invalid-feedback">Accept Ts & Cs is required</div>
          <div class="text-center">
              <button class="btn btn-primary mr-1">Submit</button>
              <button class="btn btn-secondary" type="reset" (click)="onReset()">Reset</button>

TS File

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

  selector: 'app-add-todo',
  templateUrl: './add-todo.component.html',
  styleUrls: ['./add-todo.component.scss']
export class AddTodoComponent implements OnInit {
  registerForm: FormGroup;
  submitted = false;
  constructor(private formBuilder: FormBuilder) { }

  ngOnInit() {

    this.registerForm = this.formBuilder.group({
      firstName: ['', Validators.required],
      email: ['', [Validators.required, Validators.email]],
      password: ['', [Validators.required, Validators.minLength(6)]],
      confirmPassword: ['', Validators.required],
      acceptTerms: [false, Validators.requiredTrue]

  // convenience getter for easy access to form fields
  get f() { return this.registerForm.controls; }

  onSubmit() {
    this.submitted = true;

  onReset() {
    this.submitted = false;


RegisterFormTooltipPipe (register-form-tooltip.pipe.ts)

import { Pipe, PipeTransform } from '@angular/core';
import { ValidationErrors } from '@angular/forms';

  name: 'regTooltip'
export class RegisterFormTooltipPipe implements PipeTransform {
  transform(errors: ValidationErrors, control: string): string {
    let message = '';
    switch (errors && control) {
      case 'firstName':
        message = 'Name is required';
      case 'email':
        if (errors.required) {
          message = 'Email is required';
        } else if (errors.email) {
          message = 'Email must be a valid email address';
      case 'password':
        if (errors.required) {
          message = 'Password is required';
        } else if (errors.minlength) {
          message = 'Password must be at least 6 characters'
    console.log('error on : ', control,  errors);
    return message;

App Module file

import { RegisterFormTooltipPipe } from './registration-form-tooltip.pipe';

 declarations: [

index.html scripts (Here we have used Bootstrap)

 <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>

  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>

  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">


dynamic tool tip
dynamic tooltip


import { RegisterFormTooltipPipe } from "./registration-form-tooltip.pipe";

describe('RegisterFormTooltipPipe', () => {
  let pipe;
  it('create an instance', () => {

  beforeEach(() => {
    pipe = new RegisterFormTooltipPipe();

  describe('should run transform method', () => {
    it('firstName should be required ', () => {
      const message = pipe.transform({ required: true }, 'firstName');

    it('password should be required ', () => {
      const message = pipe.transform({ required: true }, 'password');

Visit Bootstrap blog:

dynamic tooltip using pipe angular, angular tooltip dynamic, Angular Pipe to display tooltip, how to make dynamic tooltip in angular, Toolip in angular using pipe

Leave a Reply

Your email address will not be published.