Skip to content
Tippy Logo




Plugins are an extensible way to add functionality to tippy instances. By splitting functionality into a plugin, users who don't need the code provided by the plugin are not burdened with its cost by default.

#Exported plugins

These plugins are exported by the package:

  • animateFill 🖌️
  • followCursor
  • inlinePositioning
  • sticky
🖌️ Requires importing the following CSS stylesheets to work:
import 'tippy.js/dist/backdrop.css';
import 'tippy.js/animations/shift-away.css';


Note: if you are using the CDN (IIFE) version, there is no need to do the following steps. The plugins will work by default. This comes with the downside of adding extra KBs which is a tradeoff made to reduce extra HTTP requests. Using a bundler like webpack is recommended instead to benefit from treeshaking.

Pass the plugin(s) in an array as a 3rd argument to tippy():

import tippy, {followCursor} from 'tippy.js';

tippy(reference, {followCursor: true}, [followCursor]);

#Helper function

There is a helper function that returns a higher-order tippy function that will pass the plugin(s) for you:


import {createTippyWithPlugins, followCursor} from 'tippy.js';

export default createTippyWithPlugins([followCursor]);

Import tippy from this file instead of node_modules.


import tippy from './tippy';

tippy(reference, {followCursor: true});

If bundle size is important, you can create different tippy files with pass particular plugins, or stick to using the 3rd argument, so that only the routes or components that require the plugin import it.

If the cost of the plugins is neglibile for you, then you can use a central file that passes all plugins that your app requires.

#Creating your own custom plugin

A plugin is created by defining an object with the following shape:

const plugin = {
  // Optional (if the plugin provides a prop to use)
  name: 'propName', // e.g. 'followCursor' or 'sticky'
  defaultValue: 'anyValue',

  // Required
  fn(instance) {
    // Internal state
    return {
      // Lifecycle hooks

The plugin's function fn returns an object of lifecycle hooks.

Here's an example of a plugin that causes a popper to hide if no elements within it are in focus (for interactivity):

const hideOnPopperBlur = {
  name: 'hideOnPopperBlur',
  defaultValue: true,
  fn() {
    return {
      onCreate(instance) {
        instance.popper.addEventListener('focusout', event => {
          if (
            instance.props.hideOnPopperBlur &&
            event.relatedTarget &&
          ) {

// Our new prop is enabled by default (defaultValue: true)
tippy(reference, {}, [hideOnPopperBlur]);

Plugins are invoked per-instance and the plugin function definition takes the instance as an argument, so you can use private variables to create internal state in the plugin closure. This is how the followCursor plugin works.