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.
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.
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 removeddata-tippy
attribute is addeddata-original-title
attribute is added containing thetitle
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.
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:
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.
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.
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
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 :)'
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 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:
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.
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!