Using the tooltip
@flyze/lib-core-angular 1.0.0-alpha.34· latestHow to show a tooltip on hover, from imperative code, or from your own template event.
Behavior and limitations: features/tooltip.
Before anything: the CDK overlay stylesheet
Section titled “Before anything: the CDK overlay stylesheet”The panel is positioned by @angular/cdk/overlay. Without its structural CSS the tooltip renders in
the document flow instead of next to its anchor — no error, just a tooltip in the wrong place.
If your app has a Material theme you already have them, because mat.core() includes
@include cdk.overlay(). If it does not, add this once, globally:
@import '@angular/cdk/overlay-prebuilt.css';This library does not ship those rules, so nothing warns you.
On hover: the directive
Section titled “On hover: the directive”FyzTooltip is a standalone directive, so import the class — there is no module:
@Component({ standalone: true, imports: [FyzTooltip], …})In an NgModule-based component, add FyzTooltip to the module’s imports, not declarations.
<button [fyzTooltip]="'Saves the current document'">Save</button>The text is the input value, so an empty string suppresses the tooltip entirely — convenient when the text comes from data that may be missing:
<button [fyzTooltip]="row.hint">{{ row.label }}</button>Change the text while the tooltip is open and the open panel follows it, repositioning as it resizes.
Delays
Section titled “Delays”<button [fyzTooltip]="'Waited for this'" [fyzTooltipShowDelay]="600" [fyzTooltipHideDelay]="1500"> Delayed</button>fyzTooltipShowDelay stops a pointer that is only passing through from flashing a tooltip on
everything it crosses. fyzTooltipHideDelay lets a pointer that slips off an edge and comes
straight back keep the tooltip it already had — re-entering within the delay keeps the same
panel rather than building a second one.
Turning it off
Section titled “Turning it off”<button [fyzTooltip]="'Only while enabled'" [fyzTooltipDisabled]="!canSave">Save</button>Setting fyzTooltipDisabled while a tooltip is open closes that one too, immediately, regardless of
fyzTooltipHideDelay.
Styling one panel
Section titled “Styling one panel”The panel is rendered into .cdk-overlay-container at the end of <body>, so a class passed
through fyzTooltipClass must resolve globally — a component-scoped rule will not match it.
<button [fyzTooltip]="'Custom'" [fyzTooltipClass]="'my-tooltip--wide'">Hover</button><button [fyzTooltip]="'Two classes'" [fyzTooltipClass]="['my-tooltip--wide', 'my-tooltip--loud']"> Hover</button>// in a global stylesheet, not a component's.my-tooltip--wide { --fyz-tooltip-max-width: 420px;}Prefer the --fyz-tooltip-* custom properties over overriding declarations directly: the panel’s
own rules carry its encapsulation attribute, so a bare class loses the specificity contest and you
end up reaching for !important. See features/tooltip for the
full list.
From code: the service
Section titled “From code: the service”Use FyzTooltipService when the anchor is your own host element. A directive cannot be applied to
your own host from inside your own template, so a component in that position holds an HTMLElement
and nothing else.
attach() is the method to reach for. It wires the hover, resolves its options on every one, and
returns the teardown:
@Component({ selector: 'my-button', template: `<button>{{ label }}</button>` })export class MyButtonComponent implements OnDestroy { @Input() label = ''; @Input() hint = '';
readonly #stopTooltip: () => void;
constructor(host: ElementRef<HTMLElement>, tooltips: FyzTooltipService) { // A factory, not a fixed object: `hint` is an input, so it is not set yet at construction and // can change afterwards. Re-read on every hover; nullish suppresses that hover. this.#stopTooltip = tooltips.attach(host, () => (this.hint ? { text: this.hint } : null)); }
ngOnDestroy() { this.#stopTooltip(); }}Call the stop function from ngOnDestroy. It removes the listeners and disposes a panel that
may still be on screen — skip it and a tooltip outlives the element it was pointing at. It is
idempotent, so calling it twice is safe.
Pass a plain object instead of a factory when nothing changes:
tooltips.attach(host, { text: 'Static', showDelay: 300 });Opening without a hover
Section titled “Opening without a hover”tooltips.show(host, { text: 'Opened from code' });tooltips.hide(host); // honours the stored hideDelaytooltips.hide(host, 0); // override it for this callAsk the service rather than tracking state yourself — it knows about closes you did not initiate:
protected get isOpen(): boolean { return this.tooltips.isOpen(this.anchor);}
protected toggle() { this.isOpen ? this.tooltips.hide(this.anchor) : this.tooltips.show(this.anchor, { text: 'Toggled' });}Every method takes HTMLElement or ElementRef<HTMLElement>, so you can pass a @ViewChild ref
directly.
Two more, for the awkward cases:
hideImmediately(host)— no animation, no delay. For a teardown path of your own.hideAll()— closes every open panel whichever host it belongs to, ignoring each one’s delay. The escape hatch when you have lost track of your anchors, such as a route change.
If you call show() yourself, you own the teardown. attach() exists so that you usually do not.
From your own template event: exportAs
Section titled “From your own template event: exportAs”A third way in, with no service injected and no hover:
<button #tip="fyzTooltip" [fyzTooltip]="'Opened from the template'">Anchor</button>
<button (click)="tip.show()">show</button><button (click)="tip.hide()">hide</button>show() reads the same inputs a hover would, so fyzTooltipDisabled and an empty text still
suppress it.
Try it
Section titled “Try it”The /fyz-tooltip route of the playground app covers all of the above, including the cases only a
browser can show — clicking straight through a panel, long text wrapping, a panel near the viewport
edge, and light/dark theming. See the root README for running it.
Related
Section titled “Related”- features/tooltip — how it works, and its limitations
- guides/theming-an-app — the
--system-*variables the panel falls back to - guides/using-the-menu-trigger — the other CDK-overlay directive here