Misc

Event delegation

Event delegation allows you to bind a Tippy instance to a parent container element to handle creation of tippys for children.

This allows two things:

  • It eliminates the need to create new instances for new children getting appended to the parent.
  • It improves performance as only a single instance is created, and event bubbling handles creation of instances at the right time.

Children will inherit the options specified in the parent instance, but individual options can be specified via data-tippy-* attributes.

<div id="parent">
  <button class="child" data-tippy-content="Tooltip 1">One</button>
  <button 
    class="child" 
    data-tippy-content="Tooltip 2"
    data-tippy-arrow="true"
  >
    Two
  </button>
  <button 
    class="child" 
    data-tippy-content="Tooltip 3" 
    data-tippy-theme="light"
  >
    Three
  </button>
</div>

To enable this behavior, bind the instance to the #parent element and specify a target option with a CSS selector that matches the child elements which should receive tooltips.

tippy('#parent', {
  target: '.child',
})

Hide tooltips on scroll

In some cases it may be desirable to hide tooltips when scrolling (for example, on touch devices).

// Basic usage
// Note that `hideAllPoppers` won't hide a tippy if it has `hideOnClick: false`
window.addEventListener('scroll', tippy.hideAllPoppers)

// More control
window.addEventListener('scroll', () => {
  const poppers = Array.from(document.querySelectorAll('.tippy-popper'))
  poppers.forEach(popper => {
    // If you pass 0 as the duration, you can make all of them hide instantly
    popper._tippy.hide(0)
  })
})

Scrollable containers

By default, a tippy is prevented from overflowing a scrolling container (with overflow set). If the reference element is inside, the tippy can stay stuck in the container viewport while scrolling or may be positioned incorrectly in some cases. To solve this, you can use the boundary (v3.4) option and set it to window. Other values are also possible, see All Options.

tippy(ref, {
  boundary: 'window',
})

Buttons with tooltips on touch devices

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: true option 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)

/*==================================================
Make iOS behave like Android (single tap to click)
==================================================*/
button.addEventListener('click', () => {
  // Your logic
})
tippy(button, {
  onShow() {
    if (isIOS) {
      button.click()
    }
  },
})

/*==================================================
Make Android behave like iOS (double tap to click)
==================================================*/
// Useful function for dynamically determining the input type:
// https://github.com/30-seconds/30-seconds-of-code#onuserinputchange
let isUsingTouch = false
onUserInputChange(type => {
  isUsingTouch = type === 'touch'
})

const tip = tippy.one(button)
button.addEventListener('click', () => {
  if (isIOS || !isUsingTouch ? true : tip.state.isShown) {
    // Your logic
  }
})