website/src/pages/v6/plugins.mdx
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.
These plugins are exported by the package:
animateFillfollowCursorinlinePositioningstickyIncluded plugins (part of the All Props table) will work as normal.
tippy(targets, {
followCursor: true,
});
Modules have the benefit of tree-shaking, so explicitly importing the plugin is required:
import tippy, {followCursor} from 'tippy.js';
tippy(targets, {
followCursor: true,
plugins: [followCursor],
});
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. 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:
Causes a popper to hide if no elements within it are in focus.
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();
}
});
},
};
},
};
Manages tippy instances within a global store.
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);
});
}
Hides the tippy when the escape key is pressed.
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);
},
};
},
};
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>;