Skip to content
Tippy Logo


View on GitHub


#Custom position

Use a Popper ReferenceObject:

tippy(targets, {
  // popperInstance will be available onCreate
  lazy: false,
  onCreate(instance) {
    instance.popperInstance.reference = {
      clientWidth: 0,
      clientHeight: 0,
      getBoundingClientRect() {
        return {
          // ...

#Scrollable containers

While scrolling the container, the reference element can leave the boundary view, meaning the tippy will appear to be attached to nothing. You can hide the tippy to prevent it from being seen:

.tippy-tooltip[data-out-of-boundaries] {
  opacity: 0;

This may not be ideal in all cases. You can include this attribute only on a theme if necessary.

Other cases:

  • If you want the tippy to be clipped by the scrolling container, use the props appendTo: 'parent' and boundary: scrollingContainer.
  • Consider the prop flipOnUpdate: true if you want the tippy to flip to best fit in view while the container is being scrolled.

#Different trigger target

You may want the tippy to appear at a different location from its trigger (event listeners) target. For example:

Trigger target vs

For this, you can utilize the triggerTarget prop:

const innerOrangeSpanElement = document.querySelector('span');
const outerDivElement = document.querySelector('div');

tippy(innerOrangeSpanElement, {
  triggerTarget: outerDivElement

#Touch devices

Tippy provides first-class support for touch devices. Tooltips can be tricky to get right on touch devices because of the nature of touch input.


A tooltip on a button is generally used to convey information before the user decides to click on it. On touch devices, this isn't possible because a tap is required to show the tooltip, which will fire a click event.

On iOS, a tap will show the tooltip but click events won't fire until a second tap. This allows the user to see the tooltip before deciding to click the button. On Android, clicking the button will show the tooltip and also fire a click event.

Depending on your use case, one of these will be preferred, so user agent checking may be needed.

If neither behavior is preferred, consider using the touchHold prop which allows the user to see the tooltip while pressing and holding the button, but won't fire a click event unless the click appears to be intentional.

const button = document.querySelector('button');
const isIOS = /iPhone|iPad|iPod/.test(navigator.platform);
#A: Make iOS behave like Android (single tap to click)
button.addEventListener('click', () => {
  // Your logic

tippy(button, {
  onShow() {
    if (isIOS) {;
#B: Make Android behave like iOS (double tap to click)

Tippy has a useful static property tippy.currentInput. This is a mutable object whose properties change depending on the user's current input. Currently, it has a single property called isTouch, which is a boolean flag determining if the user is currently using touch input. This is a dynamic value because of hybrid devices which can use a mix of mouse and touch input.

function emulateIOS(listener) {
  let clicks = 0;

  return function() {

    if (clicks === 2 || isIOS || !tippy.currentInput.isTouch) {
      clicks = 0;
      listener.apply(this, arguments);

const instance = tippy(button);
const onClick = emulateIOS(() => {
  // Your logic

button.addEventListener('click', onClick);

#Hold & long press

// Will only show the tippy while the user is pressing the screen (not a tap)
tippy(button, {
  touch: 'hold'

// Will only show the tippy on a "long press" hold
tippy(button, {
  touch: ['hold', 500] // 500ms delay