## Tippy's features

### Default

The default tippy tooltip looks like this when given no options. It has a nifty backdrop filling animation!

### Placement

A tooltip can be placed in four different ways in relation to its reference element. Additionally, the tooltip can be shifted.

### Arrows

Arrows point toward the reference element. There are two different types of arrows: sharp and round. You can transform the proportion and scale of the arrows any way you like.

### Triggers

Triggers define the types of events that cause a tooltip to show.

### Interactivity

Tooltips can be interactive, meaning they won't hide when you hover over or click on them.

### Animations

Tooltips can have different types of animations.

### Duration

A tippy can have different transition durations.

### Delay

Tooltips can delay showing or hiding* after a trigger.

### Event delegation v2.1

Bind a Tippy instance to a parent container and freely add new child elements without needing to create Tippy instances for them.

### HTML

Tooltips can contain HTML, allowing you to craft awesome interactive popovers.

### Look! The tippy logo is inside a tippy.

### Themes

A tippy can have any kind of theme you want! Creating a custom theme is a breeze.

### Misc

Tippy has a ton of features, and it's constantly improving.

Getting started

### Option 1

Include this script from the unpkg CDN in your HTML document before your own scripts:

    <script src="https://unpkg.com/tippy.js@2.5.3/dist/tippy.all.min.js"></script>

Once it's loaded, you'll have access to the `tippy` module which will allow you to create awesome tooltips!

### Option 2

Install using either npm or yarn:

    npm install tippy.js

    yarn add tippy.js

Then you can import the `tippy` module:

    // Node environment
    const tippy = require('tippy.js')
    // With a module bundler (webpack/rollup/parcel)
    import tippy from 'tippy.js'

### Files

Tippy builds a bunch of different files that can be used:

- `tippy.all.js` is all dependencies (Tippy + Popper + CSS) in a single file. The CSS is injected into the document head.
- `tippy.js` is Tippy + Popper together, without the CSS.
- `tippy.standalone.js` is Tippy by itself, without Popper or the CSS.
- `tippy.css` is Tippy's CSS stylesheet by itself.

There are also `.min` versions of the above, which means the file is minified for production use.

Creating tooltips

### 1. Add your tooltip content

First, give your reference element(s) a title attribute containing your tooltip content.

    <button class="btn" title="I'm a tooltip!">Text</button>

If you hover over the button, you'll notice the browser's default tooltip (usually the native OS tooltip) appears after a delay.

### 2. Create a tippy

To give the elements a tippy, you'll need to add in some JavaScript inside `script` tags on your HTML page just before the closing `body` tag.

    <script>
    tippy('.btn')
    </script>

Result:

When the `tippy()` function is invoked and given a CSS selector string, it will find all the elements which match it, check if they have a non-empty `title`attribute, and then apply its magic to give them a cool tooltip.

### Mutations

The reference element(s) get modified by Tippy in the following manner:

    <!-- Before -->
    <button class="btn" title="I'm a tooltip!">Text</button>
    <!-- After -->
    <button class="btn" data-tippy data-original-title="I'm a tooltip!">Text</button>

- `title` attribute is removed
- `data-tippy` attribute is added
- `data-original-title` attribute is added containing the `title` string

Additionally, once the tooltip has fully transitioned in, an `aria-describedby` attribute is added for a11y.

### Additional input types

A single DOM `Element` (or an array of them) will work:

    tippy(document.querySelector('.btn'))

As well as a `NodeList`:

    tippy(document.querySelectorAll('.btn'))

v2.5 Use `tippy.one()` if you are creating a single tooltip. This will return the tooltip instance directly, rather than a collection object (because `tippy()` can create multiple tooltip instances at once).

    tippy.one(document.querySelector('.btn'))

### Tippify all titled elements

Use this selector:

    tippy('[title]')

### Advanced

You can use a virtual element as the positioning reference instead of a real element:

    const virtualReference = {
      attributes: {
        title: "I'm a tooltip!"
      },
      getBoundingClientRect() {
        return {
          width: 100,
          height: 100,
          top: 100,
          left: 100,
          right: 200,
          bottom: 200
        }
      },
      clientHeight: 100,
      clientWidth: 100
    }

    tippy(virtualReference)

Popper.js uses these properties to determine the position of the tooltip.

Customizing tooltips

`tippy()` takes an object of options as a second argument for you to customize the tooltips being created. Here's an example:

    tippy('.btn', {
      delay: 100,
      arrow: true,
      arrowType: 'round',
      size: 'large',
      duration: 500
      animation: 'scale'
    })

Result:

### Data attributes

You can also specify options on the reference element itself by adding `data-tippy-*` attributes. This will override the options specified in the instance.

    <button
      class="btn"
      title="I'm a Tippy tooltip!"
      data-tippy-delay="0"
      data-tippy-arrow="false"
      data-tippy-size="small"
      data-tippy-animation="shift-toward"
    >
      Text
    </button>

Result:

All options

Below is a list of all possible options you can supply to `tippy()`. The values are the default ones used, with the different inputs being listed as a comment next to it.

    tippy(ref, {
      // Available v2.3+ - If true, HTML can be injected in the title attribute
      allowTitleHTML: true,

      // If true, the tooltip's background fill will be animated (material effect)
      animateFill: true,

      // The type of animation to use
      animation: 'shift-away', // 'shift-toward', 'fade', 'scale', 'perspective'

      // Which element to append the tooltip to
      appendTo: document.body, // Element or Function that returns an element

      // Whether to display the arrow. Disables the animateFill option
      arrow: false,

      // Transforms the arrow element to make it larger, wider, skinnier, offset, etc.
      arrowTransform: '', // CSS syntax: 'scaleX(0.5)', 'scale(2)', 'translateX(5px)' etc.

      // The type of arrow. 'sharp' is a triangle and 'round' is an SVG shape
      arrowType: 'sharp', // 'round'

      // The tooltip's Popper instance is not created until it is shown for the first
      // time by default to increase performance
      createPopperInstanceOnInit: false,

      // Delays showing/hiding a tooltip after a trigger event was fired, in ms
      delay: 0, // Number or Array [show, hide] e.g. [100, 500]

      // How far the tooltip is from its reference element in pixels
      distance: 10,

      // The transition duration
      duration: [350, 300], // Number or Array [show, hide]

      // If true, whenever the title attribute on the reference changes, the tooltip
      // will automatically be updated
      dynamicTitle: false,

      // If true, the tooltip will flip (change its placement) if there is not enough
      // room in the viewport to display it
      flip: true,

      // The behavior of flipping. Use an array of placement strings, such as
      // ['right', 'bottom'] for the tooltip to flip to the bottom from the right
      // if there is not enough room
      flipBehavior: 'flip', // 'clockwise', 'counterclockwise', Array

      // Whether to follow the user's mouse cursor or not
      followCursor: false,

      // Upon clicking the reference element, the tooltip will hide.
      // Disable this if you are using it on an input for a focus trigger
      // Use 'persistent' to prevent the tooltip from closing on body OR reference
      // click
      hideOnClick: true, // false, 'persistent'

      // Specifies that the tooltip should have HTML content injected into it.
      // A selector string indicates that a template should be cloned, whereas
      // a DOM element indicates it should be directly appended to the tooltip
      html: false, // 'selector', DOM Element

      // Adds an inertial slingshot effect to the animation. TIP! Use a show duration
      // that is twice as long as hide, such as `duration: [600, 300]`
      inertia: false,

      // If true, the tooltip becomes interactive and won't close when hovered over
      // or clicked
      interactive: false,

      // Specifies the size in pixels of the invisible border around an interactive
      // tooltip that prevents it from closing. Useful to prevent the tooltip
      // from closing from clumsy mouse movements
      interactiveBorder: 2,

      // Available v2.2+ - If false, the tooltip won't update its position (or flip)
      // when scrolling
      livePlacement: true,

      // The maximum width of the tooltip. Add units such as px or rem
      // Avoid exceeding 300px due to mobile devices, or don't specify it at all
      maxWidth: '',

      // If true, multiple tooltips can be on the page when triggered by clicks
      multiple: false,

      // Offsets the tooltip popper in 2 dimensions. Similar to the distance option,
      // but applies to the parent popper element instead of the tooltip
      offset: 0, // '50, 20' = 50px x-axis offset, 20px y-axis offset

      // Callback invoked when the tooltip fully transitions out
      onHidden(instance) {},

      // Callback invoked when the tooltip begins to transition out
      onHide(instance) {},

      // Callback invoked when the tooltip begins to transition in
      onShow(instance) {},

      // Callback invoked when the tooltip has fully transitioned in
      onShown(instance) {},

      // If true, data-tippy-* attributes will be disabled for increased performance
      performance: false,

      // The placement of the tooltip in relation to its reference
      placement: 'top', // 'bottom', 'left', 'right', 'top-start', 'top-end', etc.

      // Popper.js options. Allows more control over tooltip positioning and behavior
      popperOptions: {},

      // The size of the tooltip
      size: 'regular', // 'small', 'large'

      // If true, the tooltip's position will be updated on each animation frame so
      // the tooltip will stick to its reference element if it moves
      sticky: false,

      // Available v2.1+ - CSS selector string used for event delegation
      target: null, // e.g. '.className'

      // The theme, which is applied to the tooltip element as a class name, i.e.
      // 'dark-theme'. Add multiple themes by separating each by a space, such as
      // 'dark custom'
      theme: 'dark',

      // Changes trigger behavior on touch devices. It will change it from a tap
      // to show and a tap off to hide, to a touch-and-hold to show, and a release
      // to hide
      touchHold: false,

      // The events on the reference element which cause the tooltip to show
      trigger: 'mouseenter focus', // 'click', 'manual'

      // Transition duration applied to the Popper element to transition between
      // position updates
      updateDuration: 350,

      // The z-index of the popper
      zIndex: 9999
    })

### Modifying the default options

You can modify the options by accessing them via `tippy.defaults`, which will apply to every future instance.

### More control over tooltips

Specify a `popperOptions` property with Popper.js options. View the Popper.js documentation to see all the options you can specify.

### Callbacks

If you want things to occur during tooltips' show and hide events, you can specify callback functions in the options object.

    tippy(ref, {
      onShow(instance) {
        // When the tooltip begins to transition in
      },
      onShown(instance) {
        // When the tooltip has fully transitioned in
      },
      onHide(instance) {
        // When the tooltip begins to transition out
      },
      onHidden(instance) {
        // When the tooltip has fully transitioned out and is removed from the DOM
      },
      wait(show, event) {
        // Delays showing the tooltip until you manually invoke show()
      }
    })

### AJAX tooltips

Callbacks allow you to do powerful things with tooltips. Here's an example of dynamic content which on show, fetches a new random image from the Unsplash API. Note: this requires a browser which supports the newer fetch API.

Loading...
CodePen Demo

### Event delegation v2.1

Event delegation only requires minimal setup. Your setup should look similar to this, with a parent element wrapping the child elements you would like to give tooltips to:

    <div id="parent" title="Shared title">
      <div class="child">Text</div>
      <div class="child">Text</div>
      <div class="child">Text</div>
      <div class="other">Text</div>
    </div>

Then, specify a CSS selector as the `target` that matches child elements which should receive tooltips

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

#### Note

Avoid binding a Tippy instance to the body, as `mouseover / mouseoff` events will constantly fire as the cursor moves over the page. Instead, give it to the nearest possible parent element.

#### Destroying a delegate instance

When you destroy a delegate's Tippy instance, it will destroy all target children's Tippy instances as well. To disable this behavior, pass `false` into the `destroy()` method.

    const parent = document.querySelector('#parent')
    tippy(parent, { target: '.child' })
    // Will not destroy any child target instances (if they had been created)
    parent._tippy.destroy(false)

If the target option is specified, the parent reference(s) become delegates and receive a `data-tippy-delegate` attribute instead of `data-tippy`.

    <div id="parent" title="Shared title" data-tippy-delegate></div>

### Tooltips inside a scrollable container

Add the following options to make the tooltip not stay stuck within the viewport.

    tippy('.mySelector', {
      appendTo: document.querySelector('.mySelector').parentNode,
      popperOptions: {
        modifiers: {
          preventOverflow: {
            enabled: false
          },
          hide: {
            enabled: false
          }
        }
      }
    })

### Disabling tooltips on touch devices

It can be tricky to determine touch devices accurately, especially considering the existence of hybrid devices (a mix of mouse and touch input). Simply detecting the user agent is not enough.

A user can switch between either input type at any time which is why dynamic input detection is enabled. You can hook into Tippy's detection of user input changes by defining the following callback function:

    tippy.browser.onUserInputChange = type => {
      console.log('The user is now using', type, 'as an input method')
    }

Whenever the user changes their input method, you can react to it inside the callback function. To disable tooltips for touch input but keep them enabled for mouse input, you can do the following:

    const tip = tippy('[title]')

    tippy.browser.onUserInputChange = type => {
      const method = type === 'touch' ? 'disable' : 'enable'
      for (const tooltip of tip.tooltips) {
        tooltip[method]()
      }
    }

### Hiding tooltips on scroll

Due to the way browsers fire `mouseleave` events, it may be desirable to hide tooltips and immediately disable their event listeners whenever scrolling occurs. This might also help reduce the intrusiveness of a tooltip on small screen touch devices, as it will begin hiding out of the way whenever they scroll, rather than whenever they tap somewhere else.

    window.addEventListener('scroll', () => {
      for (const popper of document.querySelectorAll('.tippy-popper')) {
        const instance = popper._tippy

        if (instance.state.visible) {
          instance.popperInstance.disableEventListeners()
          instance.hide()
        }
      }
    })

### Get all Tippy instances

Getting all (non-destroyed) Tippy instances on the document can be done in one single line:

    Array.from(document.querySelectorAll('[data-tippy]'), el => el._tippy)

This returns an array holding every current Tippy instance (excluding delegates). To include delegates, use this selector:

    '[data-tippy], [data-tippy-delegate]'

`Array.from` needs a polyfill for older browsers.

Props

It's important to distinguish between the object returned from calling `tippy()` and a Tippy instance. When you call `tippy()`, it can create multiple tooltips (Tippy instances) at once.

Tippy instances refer to individual tooltips, whereas the object returned from `tippy()` refers to the collection.

### `tippy()` object

    const tip = tippy('.btn')

`tip` is a plain object.

    {
      // selector that was supplied to tippy()
      selector: '.btn',

      // default + instance options merged together
      options: { ... },

      // Array of all Tippy instances that were created
      tooltips: [Tippy, Tippy, Tippy, ...],

      // Method to destroy all the tooltips that were created
      destroyAll() { }
    }

### Tippy instances

Stored on reference elements via the `_tippy` property, and inside the `tooltips` array of the `tippy()` object.

    tippy('.btn')
    const btn = document.querySelector('.btn')
    const tipInstance = btn._tippy

`tipInstance` is a Tippy instance.

    {
      // id of the Tippy instance (1 to Infinity)
      id: 1,

      // Popper element that contains the tooltip
      popper: Element,

      // Popper instance is not created until shown for the first time,
      // unless specified otherwise
      popperInstance: null,

      // Reference element that is the trigger for the tooltip
      reference: Element,

      // Array of objects containing the event + handler function of each trigger
      listeners: [{ ... }, { ... }, ...],

      // Defaults + instance + attribute options merged together
      options: { ... },

      // The state of the tooltip
      state: {
        // Has the instance been destroyed?
        destroyed: false,
        // Is the instance enabled?
        enabled: true,
        // Is the tooltip currently visible and not transitioning out?
        visible: false
      },

      // title content of the tooltip (null if HTML)
      title: 'example'
    }

### Shortcuts

There are several shortcuts available for accessing the instance.

    // The popper element has the instance attached to it:
    popper._tippy
    // As does the reference element (as seen above):
    reference._tippy
    // The popper also has the reference directly attached:
    popper._reference

Methods

Tippy instances have 5 methods available which allow you to control the tooltip without the use of UI events. They are:

- `Tippy.prototype.show()`
- `Tippy.prototype.hide()`
- `Tippy.prototype.enable()`
- `Tippy.prototype.disable()`
- `Tippy.prototype.destroy()`

Given the following element with a tooltip:

    <button title="Hello!">Text</button>

    const btn = document.querySelector('button')
    tippy(btn)

The Tippy instance is stored on the button element via the `_tippy` property.

v2.5 If you are dealing with a single element/tooltip, you can use `tippy.one()` method to directly return the instance instead of having to use the `_tippy` property.

    const instance = tippy.one('button')

### Show the tooltip

    btn._tippy.show()

### Hide the tooltip

    btn._tippy.hide()

### Custom transition duration

Pass a number in as an argument to override the instance option:

    btn._tippy.show(200) // 200ms
    btn._tippy.hide(1000) // 1000ms

### Disable the tooltip

The tooltip can be temporarily disabled from showing/hiding:

    btn._tippy.disable()

To re-enable:

    btn._tippy.enable()

### Destroy the tooltip

To permanently destroy the tooltip and remove all listeners from the reference element:

    btn._tippy.destroy()

The `_tippy` property is deleted from the reference element upon destruction.

### Update the tooltip

There is no method to update the tooltip content, because it's easy to do!

Option 1 (recommended): Change the title on the reference element and use the `dynamicTitle` option:

    tippy(btn, { dynamicTitle: true })
    btn.title = 'New tooltip :)'

Option 2: Manually update the tooltip:

    btn._tippy.popper.querySelector('.tippy-content').textContent = 'New tooltip :)'

Note: With the above method, `_tippy.title` won't reflect the new title, you'll need to update it manually.

If you're using an HTML template, save it to a variable reference to modify it later.

    const template = document.querySelector('template')
    tippy(btn, { html: template })
    template.textContent = 'New tooltip :)'

Creating HTML Templates

There are two ways to create an HTML template: cloning or direct reference.

### Option 1: Cloning

Clones the template's `innerHTML` but does not modify it.

Option: `html: '#templateId'` selector matching a template on the document

- Reusable
- Stays on the page
- Does not save event listeners attached to it
- Not directly modifiable

### Option 2: Direct reference

Directly appends an element to the tooltip.

Option: `html: document.querySelector('#templateId')` HTMLElement

- Can only be used once
- Removed from the page and appended to the tooltip element
- Saves event listeners attached to it
- Directly modifiable

On the document or in JavaScript somewhere, make a template.

#### Cloning

    <div id="myTemplate" style="display: none;">
      <h3>Cool <span style="color: pink;">HTML</span> inside here!</h3>
    </div>

#### Direct element reference

    <div id="myTemplate">
      <h3>Cool <span style="color: pink;">HTML</span> inside here!</h3>
    </div>

#### Dynamic element with JS

    const myTemplate = document.createElement('div')
    myTemplate.innerHTML = '<h3>Cool <span style="color: pink;">HTML</span> inside here!</h3>'

Then specify a `html` option, choosing one of the choices.

    tippy('selector', {
      html: '#myTemplate',
      // ...or...
      html: document.querySelector('#myTemplate'),
      // ...or you can clone a direct element too...
      html: document.querySelector('#myTemplate').cloneNode(true)
    })

Result:

Creating Custom Themes

Creating a theme for your tooltips is easy! If you wanted to make a theme called `honeybee`, then your CSS would look like:

    .tippy-tooltip.honeybee-theme {
      /* Your styling here. Example: */
      background-color: yellow;
      border: 2px solid orange;
      font-weight: bold;
      color: #333;
    }

The `-theme` suffix is required.

### Styling the `animateFill` backdrop

By default, tippy tooltips have a cool backdrop filling animation, which is just a circle that expands out. Its class name is `tippy-backdrop`:

    .tippy-tooltip.honeybee-theme .tippy-backdrop {
      /* Your styling here. Example: */
      background-color: yellow;
    }

If you're using the backdrop animation, avoid styling the tooltip directly – just the backdrop.

### Styling the arrow

There are two arrow selectors: `.tippy-arrow` and `.tippy-roundarrow`. The first is the pure CSS triangle shape, while the second is a custom SVG.

    .tippy-popper[x-placement^=top] .tippy-tooltip.honeybee-theme .tippy-arrow {
      /* Your styling here. */
    }

You will need to style the arrow for each different popper placement (top, bottom, left, right), which is why the selector is so long.

### Styling the content directly

    .tippy-tooltip.honeybee-theme .tippy-content {
      /* Your styling here. Example: */
      color: #333;
    }

### Specify a `theme` option

To see what your cool theme looks like, specify a `theme` option for tippy:

    tippy('.btn', {
      theme: 'honeybee',
      // ...or add multiple themes by separating each by a space...
      theme: 'honeybee bumblebee shadow'
    })

`.honeybee-theme`, `.bumblebee-theme` and `.shadow-theme` are the selectors for this theme list.

Result:

Browser support

### Current support (tracked): 96% Global, 99% USA

Tippy supports browsers with `requestAnimationFrame` and `MutationObserver` support: See caniuse data.

IE10 is only partially supported unless you polyfill `MutationObserver`, then it is fully supported. `dynamicTitle` relies on it.

Performance

On a 2016 MacBook Pro 2.6 GHz Skylake, using Chrome 65:

- Performance mode off: 13 ms per 100 elements
- Performance mode on: 6 ms per 100 elements
- Event delegation: <1 ms for 1 element!