---
title: Plugins
path: /v5/plugins/
index: 14
---

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` <Emoji emoji="🖌️" />
- `followCursor`
- `inlinePositioning`
- `sticky`

<Emoji emoji="🖌️" />
Requires importing the following CSS stylesheets to work:

```js
import 'tippy.js/dist/backdrop.css';
import 'tippy.js/animations/shift-away.css';
```

### Usage

#### CDN (iife)

Included plugins (part of the [All Props](/all-props/) table) will work as
normal.

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

#### Node (esm or cjs)

```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](/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):

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

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

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