Skip to content

Plugins

Plugins are an extensible way to add functionality to tippy instances. By splitting functionality into a plugin, components or routes that don't need the plugin are not burdened with its bundle size cost.

#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';

#Usage

#CDN (iife)

Included plugins (part of the All Props table) will work as normal.

tippy(targets, {
  followCursor: true,
});

#Node (esm or cjs)

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

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

#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(instance) {
    return {
      onCreate() {
        instance.popper.addEventListener('focusout', event => {
          if (
            instance.props.hideOnPopperBlur &&
            event.relatedTarget &&
            !instance.popper.contains(event.relatedTarget)
          ) {
            instance.hide();
          }
        });
      },
    };
  },
};

// Our new prop is enabled by default (defaultValue: true)
tippy(targets, {
  plugins: [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.

#TypeScript

Types that take Props (e.g. Tippy, Delegate, CreateSingleton) are generics that accept an extended props interface:

import tippy, {Tippy, Props, Plugin, LifecycleHooks} from 'tippy.js';

interface CustomProps {
  myCustomProp: boolean;
}

type FilteredProps = CustomProps &
  Omit<Props, keyof CustomProps | keyof LifecycleHooks>;

type ExtendedProps = FilteredProps & LifecycleHooks<FilteredProps>;

export const myCustomProp: Plugin<ExtendedProps> = {
  name: 'myCustomProp',
  defaultValue: false,
  fn: () => ({}),
};

export default (tippy as unknown) as Tippy<ExtendedProps>;