- Only enabled on mouse-driven devices
- Add various interaction animation
- API interface providing basic functions
- Lightweight, dependency free
const CustomCursor = require('custom-cursor.js').default
// Following options represent the defaults
const options = {
// Whether or not the true cursor should be hidden when the custom cursor is initialized
hideTrueCursor: false,
// Array of DOM elements/selector strings that add interactions on hover
focusElements: ['a', 'button'],
// Class applied when the true cursor is hovering over a focusElement
focusClass: 'cursor--focused',
}
// Can be selector string or DOM node
const element = '.cursor'
const customCursor = new CustomCursor(element, options)
Focus elements can be given unique interactions.
const options = {
focusElements: [
{
elements: 'a#special-focus', // Can be nodelist or selector
focusClass: 'cursor--special-focused',
mouseenter: () => {
// Run in addition to adding the focusClass
console.log('Hi!! I entered <a id="#special-focus">')
},
mouseleave: () => {
// Run in addition to removing the focusClass
console.log(`Cya!! I'm leaving <a id="#special-focus">`)
},
},
'button',
'a',
],
focusClass: 'cursor--focused',
}
const customCursor = new CustomCursor('.cursor', options)
If a focus class is given for a specific selector it will override the default. In the above example 'cursor--special-focused' is applied to <a id="special-focus">
on hover, and 'cursor--focused' is applied on hover to buttons and other links.
Note that listeners will only be attached to an element the first time it's found in the DOM when looping over the selectors. As such, the more specific an interaction, the earlier it should be specified in the array.
// Initializes the cursor to begin following the mouse by attaching listeners and starting an animation loop
customCursor.initialize()
// Disable cursor from following the mouse without removing any listeners
customCursor.disable()
// Enable cursor to follow mouse again if it has been disabled
customCursor.enable()
// Destroy the cursor removing all event listeners and stopping the animation loop
customCursor.destroy()
// Update the cursor with new options
customCursor.update(newOptions)
// Hide true cursor (if it isn't already)
customCursor.hideTrueCursor()
// Unhide true cursor (if it's hidden)
customCursor.unhideTrueCursor()
// x and y being a pixel position inside the viewport
customCursor.setPosition(x, y, (requestAnimationFrame = false))
/*
Note that if the custom cursor is still enabled it's
position will be updated on the next animationFrame.
Thus, this method is most useful when the cursor is disabled.
*/
// Add new focus control elements after initialization
customCursor.focusController.addFocusElements(focusElements)
/*
Where focusElements mimics the structure used in options when initializing the cursor
*/
// Remove elements currently applying focus controls to the cursor
customCursor.focusController.removeFocusElements(htmlElements)
/*
htmlElements are a NodeList of DOM elements currently affecting the cursor
*/
<div class="cursor"></div>
.cursor {
pointer-events: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
top: 0;
left: 0;
position: fixed;
z-index: 1000;
&.cursor--initialized {
// if cursor initialized
}
&.cursor--off-screen {
// if true cursor is outside of the window
}
&.cursor--disabled {
// if cursor has been disabled
}
}
const customCursor = new CustomCursor('.cursor').initialize()
// True when client is mobile (cursor won't get initialized)
if (customCursor.isMobileUserAgent) {
// foo()
}
Unhide hidden true cursor when disabling
const customCursor = new CustomCursor('.cursor', {
hideTrueCursor: true,
}).initialize()
// When disabling
customCursor.disable().unhideTrueCursor()
// Then re-enable
customCursor.enable().hideTrueCursor()
new CustomCursor('.cursor').setPosition(x, y).initialize()
const cursor = new CustomCursor('.cursor').initialize()
// Some time passes...
cursor.focusController.addFocusElements({
elements: '.my-new-elements'
focusClass: 'cursor--special-focused',
})
// Keep a DOM list of elements you will need to remove later
const toBeRemovedLater = document.querySelectorAll('.will-be-removed')
const cursor = new CustomCursor('.cursor', {
focusElements: [
{
elements: willBeRemovedLater
focusClass: 'cursor--special-focused',
}
]}).initialize()
// Some time passes...
cursor.focusController.removeFocusElements(toBeRemovedLater)
View Following Example's Live Demo
<div class="cursor">
<div class="cursor-border">
<span class="text">VIEW</span>
</div>
</div>
const CustomCursor = require('custom-cursor.js').default
new CustomCursor('.cursor', {
hideTrueCursor: true,
focusElements: [
{
selector: '.photo-link',
focusClass: 'cursor--focused-view',
},
'a',
],
})
.setPosition(-30, -30)
.initialize()
.cursor {
color: #ff5050;
display: none;
pointer-events: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
top: 0;
left: 0;
position: fixed;
will-change: transform;
z-index: 1000;
}
.cursor-border {
position: absolute;
box-sizing: border-box;
align-items: center;
border: 1px solid #ff5050;
border-radius: 50%;
display: flex;
justify-content: center;
height: 60px;
width: 60px;
left: 0;
top: 0;
transform: translate(-50%, -50%);
transition: all 360ms cubic-bezier(0.23, 1, 0.32, 1);
}
.cursor.cursor--initialized {
display: block;
}
.cursor .text {
font-size: 0.875rem;
opacity: 0;
transition: opacity 80ms cubic-bezier(0.23, 1, 0.32, 1);
}
.cursor.cursor--off-screen {
opacity: 0;
}
.cursor.cursor--focused .cursor-border,
.cursor.cursor--focused-view .cursor-border {
width: 90px;
height: 90px;
}
.cursor.cursor--focused-view .text {
opacity: 1;
transition: opacity 360ms cubic-bezier(0.23, 1, 0.32, 1);
}