Back to Tippyjs

Plugins

website/src/pages/v6/plugins.mdx

6.3.73.5 KB
Original Source

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

Usage

CDN (umd)

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

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

Modules (esm)

Modules have the benefit of tree-shaking, so explicitly importing the plugin is required:

js
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:

js
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. 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.

Here are some examples:

hideOnPopperBlur

Causes a popper to hide if no elements within it are in focus.

js
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();
          }
        });
      },
    };
  },
};

globalStore

Manages tippy instances within a global store.

js
let tippyInstances = [];

const globalStore = {
  fn(instance) {
    return {
      onCreate() {
        tippyInstances.push(instance);
      },
      onDestroy() {
        tippyInstances = tippyInstances.filter((i) => i !== instance);
      },
    };
  },
};

// APIs to manipulate all tippy instances
export function updateAll(props) {
  tippyInstances.forEach((instance) => {
    instance.setProps(props);
  });
}

hideOnEsc

Hides the tippy when the escape key is pressed.

js
const hideOnEsc = {
  name: 'hideOnEsc',
  defaultValue: true,
  fn({hide}) {
    function onKeyDown(event) {
      if (event.keyCode === 27) {
        hide();
      }
    }

    return {
      onShow() {
        document.addEventListener('keydown', onKeyDown);
      },
      onHide() {
        document.removeEventListener('keydown', onKeyDown);
      },
    };
  },
};
<Demo> <Tippy hideOnEsc> <Button>Focus me then press `esc`</Button> </Tippy> </Demo>

TypeScript

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

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