A lightweight, vanilla JavaScript tooltip library

v2 v1



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

Placement compare_arrows

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

Arrows play_arrow

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 touch_app

Triggers define the types of events that cause a tooltip to show. A fourth trigger, Manual, is used when you want to programmatically show or hide a tooltip.

Interactivity pan_tool

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

Animations blur_on

Tooltips can have different types of transition animations.

Transitions & Delays timer

Tooltips can have different transition durations or delays.

Themes brush

You can create all kinds of custom funky themes for your tooltips with ease.

Callbacks call

Callbacks allow you to react to a tooltip's show and hide events. Open your browser console to see when the logs occur.

HTML code

Tooltips can even contain HTML!

Misc tag_faces

Tippy has many more features! These are just some of them.

important_devices Browser support

Tippy gracefully degrades on older browsers (and with JavaScript disabled) by using the browser's default title tooltip.

Supported browsers

Browsers which support requestAnimationFrame. See caniuse. If your audience has low Opera Mini usage (common in western countries), then support should be >96%.

Touch devices

Tippy supports touch devices. Standard behavior is to tap an element to show its tooltip, and then tap elsewhere to hide it. It's also possible to change the behavior so that you can tap-and-hold to show it, then release to hide it.

Dynamic input detection

For certain options to work reliably depending on the type of user input (such as mouse or touch), dynamic input detection is enabled by default. To disable this behavior, set dynamicInputDetection to false:

tippy.browser.dynamicInputDetection = false

To see Tippy's browser settings:



Tooltips have ARIA labelling to ensure accessibility.

tag_facesGetting started

file_download Download the latest release (.zip)

Alternatively, you can install through npm:

npm install --save tippy.js@2.0.5

or use the unpkg.com CDN:


Simply include the tippy.all.min.js file in your document before your own scripts:

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

This is the bundled version which includes Popper.js and automatically injects Tippy's CSS stylesheet into the document head.

Use tippy.standalone.js if you want to use a different version of Popper.js.

buildCreating a tooltip

First, give your element(s) a title attribute containing what you want the tooltip to say.

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

Then, to give them a Tippy tooltip, call the tippy() function by passing in a CSS selector.



To give all elements with a title attribute a tooltip, you can use:


For details on the type of CSS selector string you can use, see document.querySelectorAll() for reference.

Additional selector options

You aren't limited to just a CSS selector string as input. You can also directly use a DOM element (or an array of elements):


Or a NodeList:



For more specialized cases, you can also pass in a custom virtual object instead of a DOM node to act as the positioning reference.

const refObject = {
  attributes: {
    title: 'Tooltip text'
  getBoundingClientRect() {
    return {
      top:  5 + window.pageYOffset,
      left: 5 + window.pageXOffset,
      right: 5 + window.pageXOffset,
      bottom: 220 + window.pageYOffset,
      width: 1,
      height: 1
  get clientWidth() {
    return 30
  get clientHeight() {
    return 30


Elements without a title attribute (or an empty title) and without an HTML template will not receive a tooltip.

settingsCustomizing tooltips

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

tippy('.btn', {
  placement: 'right',
  animation: 'scale',
  duration: 1000,
  arrow: true


Data attributes

You can also specify options on the element itself by adding data-tippy-* attributes. This overrides any global options specified in the instance.

  class="btn tippy"
  title="I'm a tooltip!"
  data-tippy-duration="[275, 250]"


This is helpful if you want to globally define options, but make a few tooltips different without having to call tippy() again with different options.

settings_applicationsAll options

Note: options with camelCase are lowercase in HTML. For example, animateFill is data-tippy-animatefill in HTML.

Optionsettings Defaultremove Inputssettings_input_component Rolebuild
placement 'top' 'top' 'bottom' 'left' 'right' Specifies which direction to place the tooltip in relation to the reference element. Add the suffix -start or -end to shift the placement. 'top-end' is an example.
trigger 'mouseenter focus' 'mouseenter' 'focus' 'click' 'manual' {custom} Specifies which type of events will trigger a tooltip to show. Separate each by a space. mouseenter is for hovering and touch on mobile, and focus is for keyboard navigation. Use manual if you want to show/hide the tooltip manually (see the Methods section below). {custom} refers to the fact that you can have any event listener, but it won't have the opposite "hide" event.
dynamicTitle false Boolean Whenever the title attribute on the reference element changes, the tooltip will automatically be updated.
interactive false Boolean Makes a tooltip interactive, i.e. will not close when the user hovers over or clicks on the tooltip. This lets you create a popover (similar to Bootstrap) when used in conjunction with a click trigger.
interactiveBorder 2 Number (pixels) Specifies the size of the invisible border around an interactive tooltip that will prevent it from closing. Only applies to mouseenter triggered tooltips.
animation 'shift-away' 'shift-away' 'shift-toward' 'perspective' 'fade' 'scale' Specifies the type of transition animation a tooltip has.
animateFill true Boolean Adds a material design-esque filling animation. This is disabled if you have arrow set to true.
arrow false Boolean Adds an arrow pointing to the reference element. Setting this to true disables animateFill.
arrowType 'sharp' 'sharp' 'round' Specifies the type of arrow to use. Sharp is a CSS triangle, whereas Round is a custom SVG shape.
arrowTransform '' Transform CSS Allows you to transform the arrow, such as the proportion using scale.

Because of flipping, the syntax becomes dynamic. You must use the syntax that gives the desired results for the top placement, even if you use a different placement. Only translate and scale are supported for dynamic syntax.

'scaleX(1.5)' = wider arrow
'scaleX(0.5)' = narrower arrow
'scale(0.5)' = smaller arrow
'scale(1.5)' = larger arrow
'translateY(-5px)' = arrow closer to tooltip
'translateY(5px)' = arrow farther from tooltip
delay 0 Number | Array (milliseconds) Specifies how long it takes after a show or hide event is fired for a tooltip to begin showing or hiding. Use an array to specify a different show and hide delay, such as [300, 100].
flip true Boolean Specifies whether the tooltip should flip (the reversing of placement based on the amount of room in the viewport to display a tooltip).
flipBehavior 'flip' 'flip' 'clockwise' 'counterclockwise' | Array of placement strings Specifies the flipping behavior of a tooltip. Based on the amount of room in the viewport, the tooltip will choose which placement to use. For example, 'clockwise' with a placement of 'right' will flip to the bottom when there is not enough room.
maxWidth '' String with unit Specifies the maximum width of a tooltip. Ensure you add units, such as px, rem, etc.
duration [350, 300] Number | Array (milliseconds) Specifies how long the transition animation takes to complete. A single number will use the same duration for the show and hide events. Use an array to specify a different show and hide duration, such as [300, 100].
html false false | template id | Element Allows you to add HTML to a tooltip. See Creating HTML templates.
size 'regular' 'small' 'regular' 'large' Specifies how large the tooltip is.
distance 10 Number (pixels) Specifies how far away the tooltip is from its reference element. This contrasts the offset option in that it only applies to a single axis and allows tooltips to still be interactive when their trigger is mouseenter.
theme 'dark' 'dark' You can create your own easily. See Creating themes.
offset 0 Number | String (pixels) Offsets a tooltip on a certain axis. Use a string such as '25, 10' to offset it on both the x and y axes.
hideOnClick true true false 'persistent' Specifies whether to hide a tooltip upon clicking its reference element after hovering over and when clicking elsewhere on the document. For click-triggered tooltips when using false, toggle functionality remains unless you use 'persistent'.
multiple false Boolean Specifies whether to allow multiple tooltips open on the page (click trigger only).
followCursor false Boolean Specifies whether to follow the user's mouse cursor (mouse devices only).
inertia false Boolean Modifies the transition-timing-function with a cubic bezier to create a "slingshot" intertial effect.
updateDuration 300 Number (milliseconds) Specifies the transition duration between flips and when updating a tooltip's position on the document.
sticky false Boolean Specifies whether the tooltip should stick to its reference element when it's showing (for example, if the element is animated/moves).
appendTo document.body Element | Function Specifies which element the tooltip popper is appended to. Use a function which returns an Element for more advanced use cases.
zIndex 9999 Number Specifies the z-index of the tooltip popper.
touchHold false Boolean Changes the trigger behavior on touch devices. It will change it from a tap to show and tap off to hide, to a tap and hold to show, and a release to hide.
performance false Boolean Disables data-tippy-* attribute options to make initial instantiation time faster.
onShow - Function Callback function triggered when a tooltip begins to show.
onShown - Function Callback function triggered when a tooltip has fully transitioned in.
onHide - Function Callback function triggered when a tooltip begins to hide.
onHidden - Function Callback function triggered when a tooltip has fully transitioned out.
createPopperInstanceOnInit false Boolean By default, the popper instance for a tooltip is not created until it is shown for the first time in order to optimize performance. In some cases this may cause issues, so you can specify it to be created when you init with tippy().

Safari seems to stutter slightly when the tooltip is shown for the first time. Certain CSS effects may also cause the transition to stutter on the first show. For these certain cases, you may want to set this option to true.
popperOptions {} Object Allows more control over tooltip positioning and behavior. See right below.

Modify the default options

You can change the default options by accessing them via tippy.defaults, which will apply to every tippy instance.

Finer control over tooltips

You can define a popperOptions option with Popper.js options. View the Popper.js documentation to see the options you can specify.

Tooltips inside a scrollable container

You may encounter issues with tooltip positioning when it's given to an element within a scrollable container. Firstly, when the element is no longer visible, the tooltip will stay stuck within the viewport. Secondly, it transitions between position updates. To solve this, simply specify a updateDuration of 0 and add the following popperOptions:

tippy('.mySelector', {
  updateDuration: 0,
  popperOptions: {
    modifiers: {
      preventOverflow: {
        enabled: false


If you want things to happen at certain times during a tooltip's show/hide events, you can add callback functions in the options object. There are 5 to use:

tippy('.btn', {
  onShow: function () {
    // When the tooltip has been triggered and has started to transition in
  onShown: function () {
    // When the tooltip has fully transitioned in and is showing
  onHide: function () {
    // When the tooltip has begun to transition out
  onHidden: function () {
    // When the tooltip has fully transitioned out and is hidden
  wait: function (show, event) {
    // See below for an explanation

this inside the callbacks refers to the popper being shown or hidden.

wait is a special callback that allows you to control the show method for easier integration into UI libraries like React when using HTML tooltips with components. To show the tooltip once you have done the necessary steps inside the function, simply 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 a new image...

Codepen demo


Tooltips react to content changes. For example, if a paragraph element inside the tooltip is removed or changed, the tooltip will automatically update its position.

Note: This isn't supported in IE10 natively (unless polyfilled) because it uses MutationObserver.

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 = function (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 = function (type) {
  const method = type === 'touch' ? 'disable' : 'enable'
  for (const tooltip of tip.tooltips) {

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', function () {
  const poppers = document.querySelectorAll('.tippy-popper')
  for (const popper of poppers) {
    const tooltip = popper._reference._tippy
    if (tooltip.state.visible) {


Suppose you have the following element which has been given a Tippy tooltip:

<button id="myButton" title="Tooltip">My element</button>
const btn = document.querySelector('#myButton')

Every element with a Tippy tooltip is given an attribute of data-tippy:

<button id="myButton" title="Tooltip" data-tippy>My element</button>

The Tippy instance is stored on the reference element via the _tippy property:


Tippy instances have 5 methods: enable(), disable(), show(), hide(), and destroy(). This allows you to control the tooltip without the use of UI events.

Show the tooltip


Hide the tooltip


Pass a number in as an argument to specify a custom transition duration in milliseconds:


Destroy the tooltip


Destroying the tooltip will delete the _tippy property from the reference element.

To destroy all the tooltips that were created, use the destroyAll() method on the object returned from tippy():

const tip = tippy('.btn')

tip.tooltips is an array that contains all the individual Tippy instances that were created.

Disable/enable the tooltip

In cases where you want to temporarily disable a tooltip from showing or hiding but NOT destroy it, you can use the disable() method.


To re-enable it:


Update the tooltip

In V1, for tooltips whose content needed to be changed, there was an update() method. This has been replaced by a much easier way.

For standard tooltips, simply set the dynamicTitle option to true.

tippy(btn, {
  dynamicTitle: true

Whenever the title attribute on the reference element changes, the tooltip's content will automatically be updated.

Retrieve the reference element from a popper

The reference element is attached to the popper element via the _reference property.


An example of this being useful is when handling a click event inside the popper element, and needing to know which element it refers to (and therefore its Tippy instance).


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 which can be filtered or manipulated in any way.

codeCreating HTML templates

There are two options you have when creating a template. You can either clone it or use it directly.


Use the template's id selector string.

Option: html: '#myTemplate'

  • Can be re-used multiple times
  • Not removed from the page
  • Will not save event listeners attached to it
  • Not directly modifiable


Use Element directly.

Option: html: document.querySelector('#myTemplate')

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

Example HTML template

<div id="myTemplate">
  <p>Fun <strong>non-interactive HTML</strong> here</p>
  <img alt="cat" height="150" src="img/cat.jpg">
tippy('#myElement', {
  html: document.querySelector('#myTemplate'), // Direct element option
  arrow: true,
  animation: 'fade',
  distance: 15,
  arrowTransform: 'scale(2)'


Updating tooltips with HTML content

For HTML tooltips, save your template to a variable in order to modify it later.

const template = document.querySelector('#myTemplate')
tippy(btn, {
  html: template
template.innerHTML = 'Updated!'

If you want to re-use the template multiple times, use cloneNode(true):

const template = document.querySelector('#myTemplate')
const clonedTemplate = template.cloneNode(true)
tippy(btn, {
  html: clonedTemplate
clonedTemplate.innerHTML = 'Updated!'
// template.innerHTML remains unaffected

Dynamically pulling HTML content

You can use a function instead of an element reference as the html setting. The function will be executed with one argument: the element the tooltip is being added to. This is useful for cases in which you have multiple elements, each one having its own unique tooltip.

tippy('.myElements', {
  html: el => el.querySelector('.popup')

Styling tooltips with HTML content

Use this selector to target your tooltip template. Replace "#my-template-id" with your own template's id, including the leading hash. If you're using a DOM element in the html setting and no id is found, it defaults to tippy-html-template.

.tippy-tooltip[data-template-id="#my-template-id"] {
  /* Your styling here. Example: */
  padding: 2rem;

Interactive elements also receive a class of tippy-active upon triggering so that you can still style hover effects when the user has moved the cursor away from the tooltipped element and onto the tooltip itself.

.my-tooltipped-element:hover, .my-tooltipped-element.tippy-active {
  /* Your hover styling here. */

brushCreating 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;

Themes need the -theme suffix.

Style the arrow

To style the arrow, target the element with a tippy-arrow or tippy-roundarrow class:

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

In this example, the arrow is being styled when the tooltip placement begins with top. You will need to target a specific popper placement (top, bottom, left, right) because the arrow will change based on the placement.

Sharp arrows are CSS triangles which use the border trick, while round arrows are an SVG shape which can have their color changed with fill.

Style content directly

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

Style the animateFill backdrop

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

Specify a theme

tippy('.btn', {
  theme: 'honeybee'

...or specify a data-tippy-theme attribute on the reference element.

<button class="btn tippy" title="I'm a tooltip" data-tippy-theme="honeybee">Honeybee theme</button>

Example custom theme:

Multiple themes

Add multiple themes by separating each by a space.

tippy('.btn', {
  theme: 'menu light'

This will add the classes .menu-theme and .light-theme to the tooltip's class list.


You can have thousands of tooltipped elements without affecting page performance after the initial instantiation. Tooltips are only appended to the DOM when shown, and removed when hidden. Popper.js only listens to scroll and resize events when a popper (tooltip) is showing, and also updates the position on show.

Note: these tooltips are created with performance mode set to true.


MIT. Also check Popper.js' license.

This is an example of an interactive HTML tooltip created with a template.