DEV Community

Mathias Remshardt
Mathias Remshardt

Posted on

Let's build - Autohide tooltip in Angular

The problem

We want to show/hide a tooltip for some text depending on whether there is enough room for the text.

Solution

A directive that checks the width of the text and compares it against the width of the container. If the latter is smaller than the former the tooltip will be shown.
To focus on the directive implementation we are going to use the tooltips provided by angular material.

Implementation

TooltipIfCollapsedDirective

The directive reads the width of the component it is applied to to check if the tooltip needs to enabled or disabled.

import { Directive, ElementRef, HostListener } from '@angular/core';
import { MatTooltip } from '@angular/material/tooltip';

@Directive({
  selector: '[appTooltipIfCollapsed]',
  standalone: true,
})
export class TooltipIfCollapsedDirective {
  constructor(private element: ElementRef, private tooltip: MatTooltip) {}

  ngAfterViewInit(): void {
    // The requestAnimationFrame gives the browser some time to calculate the scrollWidth which is required
    // to determine if the tooltip should be hidden or not.
    window.requestAnimationFrame(() => {
      this.updateTooltip();
    });
  }

  @HostListener('window:resize', ['$event'])
  onResize() {
    window.requestAnimationFrame(() => {
      this.updateTooltip();
    });
  }

  private updateTooltip() {
    if (
      this.element.nativeElement.getBoundingClientRect().width <
      this.element.nativeElement.scrollWidth
    ) {
      this.tooltip.disabled = false;
    } else {
      this.tooltip.disabled = true;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

It compares the width of the component against the scrollWidth. If the latter is larger than the former it means that the text does not completely fit into the container.
The first call to updateTooltip is in ngAfterViewInit so that the container width is available. The same call is made whenever the browser window is changed.

As mentioned in the comment, requestAnimationFrame gives the browser some time to recalculate the scrollWidth. Without it I had some instances where the scrollWidth was not up to date leading to the tooltip being shown/hidden when it should not.

Example

The directive is added to the node which also defines the tooltip (matToolbar in the case of Angular Material).

<div [matTooltip]="text" appTooltipIfCollapsed>
  {{ text }}
</div>
Enter fullscreen mode Exit fullscreen mode
:host {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  container-type: inline-size;
}

div {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

@container (width < 600px) {
  div {
    width: 100px;
  }
}
Enter fullscreen mode Exit fullscreen mode

For the sake of the example the width of the text container is restricted to 100px when the containing component (AppComponent) width drops below 600px.
Resizing the browser window now shows or hides the tooltip when the width is larger or smaller than 600px.

The code can be found here

Top comments (0)