Cursor Ring Hover Effect
A custom cursor ring that follows the pointer and expands when hovering over interactive elements inside the preview area.
<div class="cursor-ring-area">
<div
class="cursor-ring"
data-cursor-ring
></div>
<div class="cursor-ring-items">
<button class="cursor-ring-item">
Hover Button
</button>
<a
href="#"
class="cursor-ring-item"
>
Hover Link
</a>
</div>
</div>
.cursor-ring-area{
position:relative;
width:100%;
min-height:220px;
display:flex;
align-items:center;
justify-content:center;
overflow:hidden;
cursor:none;
}
.cursor-ring{
position:absolute;
top:0;
left:0;
z-index:10;
width:34px;
height:34px;
border:2px solid #22d3ee;
border-radius:50%;
background:rgba(34,211,238,.03);
pointer-events:none;
opacity:0;
transform:
translate(-50%, -50%);
box-shadow:
0 0 18px rgba(34,211,238,.22);
transition:
width .18s ease,
height .18s ease,
background .18s ease,
border-color .18s ease,
opacity .15s ease;
}
.cursor-ring-area:hover .cursor-ring{
opacity:1;
}
.cursor-ring.active{
width:64px;
height:64px;
background:
rgba(34,211,238,.10);
border-color:#8b5cf6;
box-shadow:
0 0 28px rgba(139,92,246,.25);
}
.cursor-ring-items{
position:relative;
z-index:2;
display:flex;
align-items:center;
justify-content:center;
flex-wrap:wrap;
gap:18px;
}
.cursor-ring-item{
padding:14px 20px;
border:1px solid #263750;
border-radius:10px;
background:#0b1423;
color:#ffffff;
font-size:14px;
font-weight:700;
text-decoration:none;
cursor:none;
transition:
background .2s ease,
border-color .2s ease,
transform .2s ease;
}
.cursor-ring-item:hover{
background:#101c2e;
border-color:#22d3ee;
transform:
translateY(-2px);
}
const area =
document.querySelector('.cursor-ring-area');
if (area) {
const ring =
area.querySelector('[data-cursor-ring]');
area.addEventListener(
'mousemove',
function(event) {
if (!ring) {
return;
}
const rect =
area.getBoundingClientRect();
ring.style.left =
event.clientX -
rect.left +
'px';
ring.style.top =
event.clientY -
rect.top +
'px';
}
);
area.addEventListener(
'mouseover',
function(event) {
const item =
event.target.closest(
'.cursor-ring-item'
);
if (!item) {
return;
}
if (!ring) {
return;
}
ring.classList.add(
'active'
);
}
);
area.addEventListener(
'mouseout',
function(event) {
const item =
event.target.closest(
'.cursor-ring-item'
);
if (!item) {
return;
}
if (item.contains(event.relatedTarget)) {
return;
}
if (!ring) {
return;
}
ring.classList.remove(
'active'
);
}
);
area.addEventListener(
'click',
function(event) {
const link =
event.target.closest(
'a.cursor-ring-item'
);
if (!link) {
return;
}
event.preventDefault();
}
);
}
How This Component Works
This component replaces the default mouse pointer with a custom ring that tracks cursor movement in real time. The HTML sets up a container (cursor-ring-area) holding two things: a single ring element (cursor-ring) and a group of interactive items — a button and a link — that the ring reacts to.
The JavaScript listens for mousemove on the entire document, but only acts when the cursor is inside a .cursor-ring-area container. On every movement, it calculates the cursor’s position relative to that container and updates the ring’s left and top values directly, so the ring follows the pointer smoothly. Because the CSS also applies a translate(-50%, -50%) transform, the ring stays perfectly centered on the cursor rather than trailing from its top-left corner.
The “hover to expand” behavior comes from two more event listeners: mouseover and mouseout. Internally, the script uses the closest() method to detect whether the hovered element is a cursor-ring-item (the button or link), then JavaScript adds an active class to the ring.
Customization Tips
Everything about this cursor ring hover effect can be adjusted from the CSS file without touching the JavaScript:
- Change the default ring color — update the
borderandbox-shadowcolors in.cursor-ring(currently cyan). - Change the “active” hover color — update
border-colorandbox-shadowinside.cursor-ring.active(currently purple) to match your brand. - Adjust the expand size — increase or decrease the
width/heightvalues in.cursor-ring.activefor a bigger or smaller expansion effect. - Control animation speed — the
transitiondurations (currently.18s) can be shortened for a snappier feel or lengthened for a smoother one. - Style the interactive items — the button and link styling live in
.cursor-ring-item, independent of the ring itself.
Where to Use This
Because this effect is built around hover states on specific elements, it works best wherever you want to draw attention to clickable items:
- Navigation menus and buttons, where the ring naturally highlights which item the user is about to click.
- Portfolio or agency websites, especially around call-to-action buttons like “Contact” or “View Work.”
- Interactive link lists, such as a set of social or project links, where the expanding ring gives clear visual feedback.
This effect is not meant to be used across large blocks of text or content-heavy sections — it’s designed specifically for discrete, clickable elements, not full-page tracking.
If you’d prefer a softer, glowing trail instead of a ring, take a look at our Gradient Cursor Trail component for a similar hover-based approach with a different visual style.
Frequently Asked Questions
Does this work on touch devices?
No, and it’s designed not to. Since touch devices don’t have a hover state or a visible cursor, the component automatically hides the ring and restores the normal cursor on smaller screens via a mobile media query, so nothing breaks or looks out of place.
Can I add more interactive items to the ring’s hover detection?
Yes. Any element you give the class cursor-ring-item will automatically trigger the ring’s expand effect on hover — you don’t need to modify the JavaScript to add more buttons or links.
Why does the ring sometimes lag slightly behind fast mouse movements?
This is expected with any cursor-following effect built on the mousemove event, since the ring’s position updates on each event fire rather than continuously. The lag is minimal and generally not noticeable during normal use.
What makes this cursor ring hover effect different from a simple cursor dot?
Unlike a basic dot that just follows the mouse, this cursor ring hover effect reacts to what’s underneath it — expanding, changing color, and glowing only when hovering over clickable items like buttons or links. This gives users clear visual feedback about what’s interactive on the page.
