Skip to content

Instantly share code, notes, and snippets.

@max-lt
Last active December 30, 2023 12:39
Show Gist options
  • Save max-lt/ada60b13cb7ba4425220b6bf62d8f274 to your computer and use it in GitHub Desktop.
Save max-lt/ada60b13cb7ba4425220b6bf62d8f274 to your computer and use it in GitHub Desktop.
Angular tooltip
import { Directive, ElementRef, HostListener, Input, OnInit, Renderer2 as Renderer } from '@angular/core';
@Directive({ selector: '[tooltip]' })
export class TooltipDirective implements OnInit {
private tooltip!: HTMLElement;
@Input('tooltip')
content!: string;
@Input()
placement?: string;
@HostListener('mouseenter')
onMouseEnter() {
this.tooltip.classList.remove('hidden');
this.setPosition();
this.tooltip.classList.add('display');
}
@HostListener('mouseleave')
onMouseLeave() {
this.tooltip.classList.remove('display');
setTimeout(() => this.tooltip.classList.add('hidden'), 200);
}
constructor(private el: ElementRef<HTMLElement>, private renderer: Renderer) {}
ngOnInit() {
const tooltip = this.renderer.createElement('span');
tooltip.innerText = this.content;
this.renderer.addClass(tooltip, 'hidden');
this.renderer.addClass(tooltip, 'ng-tooltip');
this.renderer.addClass(tooltip, this.placement ?? 'left');
this.tooltip = this.el.nativeElement.appendChild(tooltip);
}
private setPosition() {
const hostPos = this.el.nativeElement.getBoundingClientRect();
const tooltipPos = this.tooltip.getBoundingClientRect();
const scrollPos = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
let top = 0;
let left = 0;
let offset = 10;
switch (this.placement) {
case 'top':
top = hostPos.top - tooltipPos.height - offset;
left = hostPos.left + (hostPos.width - tooltipPos.width) / 2;
break;
case 'bottom':
top = hostPos.bottom + offset;
left = hostPos.left + (hostPos.width - tooltipPos.width) / 2;
break;
case 'left':
top = hostPos.top + (hostPos.height - tooltipPos.height) / 2;
left = hostPos.left - tooltipPos.width - offset;
break;
case 'right':
top = hostPos.top + (hostPos.height - tooltipPos.height) / 2;
left = hostPos.right + offset;
break;
}
this.renderer.setStyle(this.tooltip, 'top', `${top + scrollPos}px`);
this.renderer.setStyle(this.tooltip, 'left', `${left}px`);
}
}
/* Tooltip */
.ng-tooltip {
position: absolute;
max-width: 150px;
font-size: 14px;
text-align: center;
color: var(--bg-primary);
padding: 3px 8px;
background: var(--color-primary);
z-index: 1000;
opacity: 0;
transition: opacity 200ms;
&.display {
opacity: 1 !important;
}
&:after {
content: '';
border-width: 5px;
position: absolute;
border-style: solid;
}
&.top {
&:after {
top: 100%;
left: 50%;
margin-left: -5px;
border-color: var(--color-primary) transparent transparent transparent;
}
}
&.bottom {
&:after {
bottom: 100%;
left: 50%;
margin-left: -5px;
border-color: transparent transparent var(--color-primary) transparent;
}
}
&.left {
&:after {
top: 50%;
left: 100%;
margin-top: -5px;
border-color: transparent transparent transparent var(--color-primary);
}
}
&.right {
&:after {
top: 50%;
right: 100%;
margin-top: -5px;
border-color: transparent var(--color-primary) transparent transparent;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment