
Security News
Meet Socket at Black Hat Europe and BSides London 2025
Socket is heading to London! Stop by our booth or schedule a meeting to see what we've been working on.
@gwlab/mouse-follower
Advanced tools
This is a Typescript continuation of the original Mouse Follower library by Cuberto. I just want to make it with type definitions and css swiper like styles with css-variables. Maybe I will add some new features in the future. If you have any ideas or suggestions, feel free to open an issue or pull request.
MIT License © 2024-PRESENT Greenwich Lab
GSAP v3 (https://greensock.com/gsap/)
Import GSAP and Mouse Follower and initialize it:
import MouseFollower from '@gwlab/mouse-follower'
import gsap from 'gsap'
MouseFollower.registerGSAP(gsap)
const cursor = new MouseFollower()
Don't forget to import the cursor styles from /dist/css/mouse-follower.css into your styles:
@import '@gwlab/mouse-follower/dist/css/mouse-follower.css';
To style the cursor, you can use the following css variables: docs link
:root {
--mf-color-base: #000;
--mf-color-text: #fff;
--mf-color-base-invert: #fff;
--mf-cursor-size: 48px;
--mf-cursor-default-scale: 0.2;
--mf-cursor-text-size: 36px;
--mf-cursor-text-font-size: 16px;
--mf-cursor-text-line-height: 20px;
--mf-cursor-text-letter-spacing: initial;
--mf-cursor-media-size: 400px;
--mf-cursor-pointer-scale: 0.15;
--mf-cursor-text-scale: 1.7;
--mf-cursor-text-scale-active: 1.6;
--mf-cursor-icon-scale: 1.5;
--mf-cursor-icon-active-scale: 1.4;
}
You can configure Mouse Follower via options:
const cursor = new MouseFollower({
container: '.mf-container',
speed: 0.3
})
The following options with defaults are available:
const cursor = new MouseFollower({
el: null,
container: document.body,
className: 'mf-cursor',
innerClassName: 'mf-cursor-inner',
textClassName: 'mf-cursor-text',
mediaClassName: 'mf-cursor-media',
mediaBoxClassName: 'mf-cursor-media-box',
iconSvgClassName: 'mf-svgsprite',
iconSvgNamePrefix: '-',
iconSvgSrc: '',
dataAttr: 'cursor',
hiddenState: '-hidden',
textState: '-text',
iconState: '-icon',
activeState: '-active',
mediaState: '-media',
stateDetection: {
'-pointer': 'a,button',
'-hidden': 'iframe'
},
visible: true,
visibleOnState: false,
speed: 0.55,
ease: 'expo.out',
overwrite: true,
skewing: 0,
skewingText: 2,
skewingIcon: 2,
skewingMedia: 2,
skewingDelta: 0.001,
skewingDeltaMax: 0.15,
stickDelta: 0.15,
showTimeout: 20,
hideOnLeave: true,
hideTimeout: 300,
hideMediaTimeout: 300
})
| Name | Type | Description |
|---|---|---|
el | string | HTMLElement | Existed cursor element. If not specified, the cursor will be created automatically. |
container | string | HTMLElement | Cursor container. Body by default. |
className | string | Cursor root element class name. |
innerClassName | string | Inner element class name. |
textClassName | string | Text element class name. |
mediaClassName | string | Media element class name. |
mediaBoxClassName | string | Media inner element class name. |
iconSvgClassName | string | SVG sprite class name. |
iconSvgNamePrefix | string | SVG sprite class name prefix of icon. |
iconSvgSrc | string | SVG sprite source. If you are not using SVG sprites leave this blank. |
dataAttr | string | null | Name of data attribute for changing cursor state directly in HTML markdown. Uses an event delegation. |
hiddenState | string | Hidden class name state. |
textState | string | Text class name state. |
iconState | string | Icon class name state. |
activeState | string | null | Active (mousedown) class name state. Set false to disable. |
mediaState | string | Media (image/video) class name state. |
visible | boolean | Is cursor visible by default. |
visibleOnState | boolean | Automatically show/hide cursor when state added. Can be useful when implementing a hidden cursor follower. |
stateDetection | object | null | Allow to set predefined states for different elements on page. Uses an event delegation. |
speed | number | Cursor movement speed. |
ease | string | Timing function of cursor movement. See gsap easing. |
overwrite | boolean | Overwrite or remain cursor position when mousemove event happened. See gsap overwrite modes. |
skewing | number | Default "skewing" factor. |
skewingText | number | Skew effect factor in a text state. Set 0 to disable skew in this mode. |
skewingIcon | number | Skew effect factor in a icon state. Set 0 to disable skew in this mode. |
skewingMedia | number | Skew effect factor in a media (image/video) state. Set 0 to disable skew in this mode. |
skewingDelta | number | Skew effect base delta. Set 0 to disable skew in this mode. |
skewingDeltaMax | number | Skew effect max delta. Set 0 to disable skew in this mode. |
stickDelta | number | Stick effect delta. |
showTimeout | number | Delay before show. May be useful for the spawn animation to work properly. |
hideOnLeave | boolean | Hide the cursor when mouse leave container. |
hideTimeout | number | Hiding delay. Should be equal to the CSS hide animation time. |
initialPos | array | Array (x, y) of initial cursor position. |
These basic methods allow you to show and hide the cursor:
const cursor = new MouseFollower()
const el = document.querySelector('.my-element')
el.addEventListener('mouseenter', () => {
cursor.hide()
})
el.addEventListener('mouseleave', () => {
cursor.show()
})
or via data attribute:
<div data-cursor="-hidden">Hover me to hide cursor!</div>
A state is essentially a class that applies to the root element of the cursor. You can change the appearance of the
cursor using CSS (see cursor.scss).
To set/unset state use methods:
const cursor = new MouseFollower()
const el = document.querySelector('.my-element')
el.addEventListener('mouseenter', () => {
cursor.addState('-inverse') // you can pass multiple states separated by whitespace
})
el.addEventListener('mouseleave', () => {
cursor.removeState('-inverse')
})
or via data attribute:
<div data-cursor="-inverse">Hover me to inverse cursor!</div>
You can customize the list of states for all elements on the page:
const cursor = new MouseFollower({
stateDetection: {
'-pointer': 'a,button',
'-opaque': '.my-image',
'-hidden': '.my-input'
}
})
<a>On this element cursor will be in pointer state</a>
<div class="my-image">On this element cursor will be in opaque state</div>
<div class="my-input">On this element cursor will be hidden</div>
Note: State detection feature uses an event delegation. Do not create large amount rules and complex selectors to avoid performance problems. It is recommended to disable this in projects with a large number of nested DOM elements. This also applies to binding via data attribute.
To fully disable event delegation:
const cursor = new MouseFollower({
stateDetection: false,
dataAttr: false
})
To display text in the cursor use this method:
const cursor = new MouseFollower()
const el = document.querySelector('.my-element')
el.addEventListener('mouseenter', () => {
cursor.setText('Hello!')
})
el.addEventListener('mouseleave', () => {
cursor.removeText()
})
or via data attribute:
<div data-cursor-text="Hello!">Hover me!</div>
If you use SVG spritesheet in your project and want to display them in the cursor, then you can use this method. In this case, you need to specify the path to the SVG sprite in the options and set class names.
const cursor = new MouseFollower({
iconSvgSrc: '/assets/img/sprites/svgsprites.svg',
iconSvgClassName: 'my-spritesheet',
iconSvgNamePrefix: '-',
})
const el = document.querySelector('.my-element')
el.addEventListener('mouseenter', () => {
cursor.setIcon('arrow-left')
})
el.addEventListener('mouseleave', () => {
cursor.removeIcon()
})
or via data attribute:
<div data-cursor-icon="arrow-left">Hover me!</div>
This method allows you to show any picture in the cursor:
const cursor = new MouseFollower()
const el = document.querySelector('.my-element')
el.addEventListener('mouseenter', () => {
cursor.setImg('/img/example.png')
})
el.addEventListener('mouseleave', () => {
cursor.removeImg()
})
or via data attribute:
<div data-cursor-img="/img/example.png">Hover me to show image!</div>
You can also play videos:
const cursor = new MouseFollower()
const el = document.querySelector('.my-element')
el.addEventListener('mouseenter', () => {
cursor.setVideo('/video/example.mp4')
})
el.addEventListener('mouseleave', () => {
cursor.removeVideo()
})
or via data attribute:
<div data-cursor-video="/video/example.mp4">Hover me to show movie!</div>
This method allows you to attach the cursor to an element with a magnet effect. This only works correctly with fixed elements on the page.
const cursor = new MouseFollower()
const box = document.querySelector('.my-fixed-box')
const el = document.querySelector('.my-fixed-element')
box.addEventListener('mouseenter', () => {
cursor.setStick(el)
})
box.addEventListener('mouseleave', () => {
cursor.removeStick()
})
or via data attribute:
<div data-cursor-stick>Hover me to stick cursor!</div>
You can also pass element selector to data attribute:
<div data-cursor-stick="#stick-me">Hover <div id="stick-me">me</div> to stick cursor!</div>
The skew effect is the distortion of the cursor when moving. It looks good with round cursors.
const cursor = new MouseFollower()
const el = document.querySelector('.my-element')
el.addEventListener('mouseenter', () => {
cursor.setSkewing(3)
})
el.addEventListener('mouseleave', () => {
cursor.removeSkewing()
})
In this example, the cursor is initialized hidden by default and only appears on the desired element.
const cursor = new MouseFollower({
visible: false
})
const el = document.querySelector('.my-element')
el.addEventListener('mouseenter', () => {
cursor.show()
cursor.setText('Surprise!')
})
el.addEventListener('mouseleave', () => {
cursor.removeText()
cursor.hide()
})
or via data attribute:
<div data-cursor-show data-cursor-text="Surprise!">Hover me to show cursor!</div>
Destroy the cursor completely and remove all event listeners.
const cursor = new MouseFollower()
cursor.destroy()
Mouse Follower comes with a useful events you can listen. Events can be assigned in this way:
const cursor = new MouseFollower()
cursor.on('show', () => {
console.log('cursor appear')
})
You can also delete an event that you no longer want to listen in these ways:
cursor.off('show')
cursor.off('show', myHandler)
| Name | Arguments | Description |
|---|---|---|
show | (cursor) | Event will be fired when the show state is entered. |
hide | (cursor) | Event will be fired when the hidden state is entered. |
addState | (cursor, state) | Event will be fired when the state is added. |
removeState | (cursor, state) | Event will be fired when the state is removed. |
render | (cursor) | Event will be fired on each render tick. |
destroy | (cursor) | Event will be fired when the instance is destroyed. |
FAQs
_description_
We found that @gwlab/mouse-follower demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Socket is heading to London! Stop by our booth or schedule a meeting to see what we've been working on.

Security News
OWASP’s 2025 Top 10 introduces Software Supply Chain Failures as a new category, reflecting rising concern over dependency and build system risks.

Research
/Security News
Socket researchers discovered nine malicious NuGet packages that use time-delayed payloads to crash applications and corrupt industrial control systems.