@ngneat/helipopper vs ngx-popperjs
Angular Popper.js Integrations Comparison
1 Year
@ngneat/helipopperngx-popperjsSimilar Packages:
What's Angular Popper.js Integrations?

Both @ngneat/helipopper and ngx-popperjs are Angular libraries designed to facilitate the integration of Popper.js, a powerful positioning engine for tooltips and popovers. They provide developers with the ability to create dynamic and responsive UI elements that can be positioned relative to other elements on the page. While both libraries serve a similar purpose, they differ in terms of features, ease of use, and customization options, making them suitable for different types of projects and developer preferences.

Package Weekly Downloads Trend
Github Stars Ranking
Stat Detail
Package
Downloads
Stars
Size
Issues
Publish
License
@ngneat/helipopper19,223423121 kB29a month agoMIT
ngx-popperjs18,26167253 kB0a month agoMIT
Feature Comparison: @ngneat/helipopper vs ngx-popperjs

API Design

  • @ngneat/helipopper:

    @ngneat/helipopper provides a more modern and Angular-centric API that leverages Angular's reactive programming principles. It allows developers to easily manage the lifecycle of poppers through Angular's dependency injection and change detection, resulting in a more intuitive integration with Angular applications.

  • ngx-popperjs:

    ngx-popperjs offers a simpler API that is easy to understand and implement. It focuses on providing essential features for tooltips and popovers without overwhelming developers with advanced options, making it suitable for quick implementations.

Customization Options

  • @ngneat/helipopper:

    @ngneat/helipopper allows for extensive customization of popper behavior and appearance. Developers can easily modify the positioning, styling, and animations of poppers, providing greater control over the user experience.

  • ngx-popperjs:

    ngx-popperjs offers basic customization options but may be limited compared to @ngneat/helipopper. It is suitable for developers who need standard tooltip and popover features without the need for deep customization.

Integration with Angular Features

  • @ngneat/helipopper:

    This package is designed to work seamlessly with Angular's reactive features, such as observables and change detection. This makes it easier to manage dynamic content and updates, ensuring that poppers behave correctly in response to application state changes.

  • ngx-popperjs:

    While ngx-popperjs can be integrated with Angular, it does not leverage Angular's reactive features as effectively as @ngneat/helipopper. This may lead to more manual management of state and updates.

Performance

  • @ngneat/helipopper:

    @ngneat/helipopper is optimized for performance in Angular applications, ensuring that poppers are rendered efficiently and only when necessary. This can lead to improved application responsiveness, especially in complex UIs.

  • ngx-popperjs:

    ngx-popperjs provides decent performance but may not be as optimized for Angular's change detection and lifecycle management, potentially leading to unnecessary re-renders in certain scenarios.

Documentation and Community Support

  • @ngneat/helipopper:

    @ngneat/helipopper has comprehensive documentation and an active community, making it easier for developers to find resources, examples, and support when implementing the library in their projects.

  • ngx-popperjs:

    ngx-popperjs has basic documentation, which may be sufficient for simple use cases but might lack depth for more complex implementations. The community support may also be less active compared to @ngneat/helipopper.

How to Choose: @ngneat/helipopper vs ngx-popperjs
  • @ngneat/helipopper:

    Choose @ngneat/helipopper if you need a more modern and flexible API that integrates seamlessly with Angular's reactive programming model. It offers better support for Angular features like observables and change detection, making it ideal for applications that require dynamic positioning and responsiveness.

  • ngx-popperjs:

    Choose ngx-popperjs if you prefer a straightforward implementation with a focus on simplicity and ease of use. It is suitable for projects that require basic tooltip and popover functionality without the need for extensive customization or advanced features.

README for @ngneat/helipopper


MIT commitizen PRs styled with prettier All Contributors ngneat spectator @ngneat/helipopper

A Powerful Tooltip and Popover for Angular Applications

Tippy.js is the complete tooltip, popover, dropdown, and menu solution for the web, powered by Popper.js.

It is an abstraction over Popper that provides the logic and optionally the styling involved in all types of elements that pop out from the flow of the document and get overlaid on top of the UI, positioned next to a reference element.

This is a lightweight wrapper with additional features that lets you use it declaratively in Angular. Tippy has virtually no restrictions over Popper and gives you limitless control while providing useful behavior and defaults.

If you're using v1 and don't want to migrate, you can find it here.

Features

✅ Position Tooltips, Menus, Dropdowns, and Popovers
✅ Predefined Variations
✅ TemplateRef/Component Support
✅ Lazy Registration
✅ Manual Trigger Support
✅ Text Overflow Support
✅ Context Menu Support

Installation

$ npm i @ngneat/helipopper
# Or if you're using yarn
$ yarn add @ngneat/helipopper
# Or if you're using pnpm
$ pnpm i @ngneat/helipopper

Configure it as shown below:

import { provideTippyLoader provideTippyConfig, tooltipVariation, popperVariation } from '@ngneat/helipopper/config';

bootstrapApplication(AppComponent, {
  providers: [
    provideTippyLoader(() => import('tippy.js')),
    provideTippyConfig({
      defaultVariation: 'tooltip',
      variations: {
        tooltip: tooltipVariation,
        popper: popperVariation,
      },
    }),
  ],
});

Please note that the provideTippyLoader is required, as it specifies how Tippy is loaded - either synchronously or asynchronously. When dynamic import is used, the library will load only when the first Tippy directive is rendered. If we want it to load synchronously, we use the following:

import tippy from 'tippy.js';

provideTippyLoader(() => tippy);

Add the styles you want to styles.scss:

@import 'tippy.js/dist/tippy.css';
@import 'tippy.js/themes/light.css';
@import 'tippy.js/animations/scale.css';

You have the freedom to customize it if you need to.

Import the standalone TippyDirective in your components:

import { TippyDirective } from '@ngneat/helipopper';

@Component({
  standalone: true,
  imports: [TippyDirective],
})
class ExampleComponent {}

And use it in your templates:

<button tp="Helpful Message">I have a tooltip</button>

The library exposes default variations for tooltip and popper. You can use them, extend them, or pass your own variations. A variation is a set of predefined tippy properties. For example, here's how the built-in tooltip variation looks like:

export const tooltipVariation = {
  theme: null,
  arrow: false,
  animation: 'scale',
  trigger: 'mouseenter',
  offset: [0, 5],
};

Use TemplateRef as content

<button [tp]="tpl" tpVariation="popper">Click Me</button>

<ng-template #tpl let-hide>
  <h6>Popover title</h6>
  <p>And here's some amazing content. It's very engaging. Right?</p>
</ng-template>

Use Component as content

import type { TippyInstance } from '@ngneat/helipopper/config';
import { injectTippyRef } from '@ngneat/helipopper';

@Component()
class MyComponent {
  tippy = injectTippyRef();
}
<button [tp]="MyComponent">Click Me</button>

Text Overflow

You can pass the onlyTextOverflow input to show the tooltip only when the host overflows its container:

<div style="max-width: 100px;" class="overflow-hidden flex">
  <p class="ellipsis" [tp]="text" tpPlacement="right" [tpOnlyTextOverflow]="true">
    {{ text }}
  </p>
</div>

Note: this feature is using ResizeObserver api.

You might have cases where the host has a static width and the content is dynamic. In this case, use the tpStaticWidthHost input with combination with tpOnlyTextOverflow:

<div style="max-width: 100px;" class="overflow-hidden flex">
  <p
    style="width: 100px"
    class="ellipsis"
    [tp]="dynamicText"
    tpPlacement="right"
    [tpOnlyTextOverflow]="true"
    tpStaticWidthHost
  >
    {{ dynamicText }}
  </p>
</div>

Note: when using tpStaticWidthHost you can't use tpUseTextContent, you need to explicitly pass the content to tp in order to trigger content change.

Use Text Content

You can instruct tippy to use the element textContent as the tooltip content:

<p tp tpUseTextContent>{{ text }}</p>

Lazy

You can pass the tpIsLazy input when you want to defer the creation of tippy only when the element is in the view:

<div *ngFor="let item of items" [tp]="item.label" [tpIsLazy]="true">{{ item.label }}</div>

Note that it's using IntersectionObserver api.

Context Menu

First, define the contextMenu variation:

import {
  popperVariation,
  tooltipVariation,
  provideTippyConfig,
  withContextMenuVariation,
} from '@ngneat/helipopper/config';

bootstrapApplication(AppComponent, {
  providers: [
    provideTippyConfig({
      defaultVariation: 'tooltip',
      variations: {
        tooltip: tooltipVariation,
        popper: popperVariation,
        contextMenu: withContextMenuVariation(popperVariation),
      },
    }),
  ],
});

Now you can use it in your template:

<ng-template #contextMenu let-hide let-item="data">
  <ul>
    <li (click)="copy(item); hide()">Copy</li>
    <li (click)="duplicate(item); hide()">Duplicate</li>
  </ul>
</ng-template>

<ul>
  <li
    *ngFor="let item of list"
    [tp]="contextMenu"
    [tpData]="item"
    tpVariation="contextMenu"
  >
    {{ item.label }}
  </li>
</ul>

Manual Trigger

<div tp="Helpful Message" tpTrigger="manual" #tooltip="tippy">Click Open to see me</div>

<button (click)="tooltip.show()">Open</button>
<button (click)="tooltip.hide()">Close</button>

Declarative show/hide

Use isVisible to trigger show and hide. Set trigger to manual.

<div tp="Helpful Message" tpTrigger="manual" [tpIsVisible]="visibility">
  Click Open to see me
</div>

<button (click)="visibility = true">Open</button>
<button (click)="visibility = false">Close</button>

You can see more examples in our playground, or live here.

Inputs

tp: string | TemplateRef<any> | Type<any> | undefined | null;
tpAppendTo: TippyProps['appendTo'];
tpDelay: TippyProps['delay'];
tpDuration: TippyProps['duration'];
tpHideOnClick: TippyProps['hideOnClick'];
tpInteractive: TippyProps['interactive'];
tpInteractiveBorder: TippyProps['interactiveBorder'];
tpMaxWidth: TippyProps['maxWidth'];
tpOffset: TippyProps['offset'];
tpPlacement: TippyProps['placement'];
tpPopperOptions: TippyProps['popperOptions'];
tpShowOnCreate: TippyProps['showOnCreate'];
tpTrigger: TippyProps['trigger'];
tpTriggerTarget: TippyProps['triggerTarget'];
tpZIndex: TippyProps['zIndex'];
tpAnimation: TippyProps['animation'];
tpUseTextContent: boolean;
tpIsLazy: boolean;
tpVariation: string;
tpIsEnabled: boolean;
tpIsVisible: boolean;
tpClassName: string;
tpOnlyTextOverflow: boolean;
tpData: any;
tpUseHostWidth: boolean;
tpHideOnEscape: boolean;
tpDetectChangesComponent: boolean;
tpPopperWidth: number | string;
tpHost: HTMLElement;
tpIsVisible: boolean;

Outputs

tpVisible = new EventEmitter<boolean>();

Global Config

  • You can pass any tippy option at global config level.
  • beforeRender - Hook that'll be called before rendering the tooltip content ( applies only for string )

Create tippy Programmatically

import type { TippyInstance } from '@ngneat/helipopper/config';
import { TippyService } from '@ngneat/helipopper';

class Component {
  @ViewChild('inputName') inputName: ElementRef;
  tippy: TippyInstance;
  private tippyService = inject(TippyService);

  async show() {
    if (!this.tippy) {
      this.tippy = await firstValueFrom(
        this.tippyService.create(this.inputName, 'this field is required')
      );
    }

    this.tippy.show();
  }

  ngOnDestroy() {
    this.tippy?.destroy();
  }
}

Contributors ✨

Thank goes to all these wonderful people who contributed ❤️