Today, I was working on a custom slider using SwiperJS, and I wanted to do something a bit more interactive than the usual arrows or dots.
Instead of showing fixed navigation arrows, I thought it would be more fun to show floating “Next” and “Previous” text that follow the cursor, depending on which side of the slider you’re hovering. Kind of like a tail that hints where the slider will move if you click.
It turned out to be a really nice effect – but getting it right wasn’t completely straightforward. Here’s how I made it work, and what issues came up along the way.
What I Was Trying to Do
- Show “Next” on the right side of the slider
- Show “Previous” on the left
- Make the text follow the cursor with a smooth animation (like a trailing effect)
- Hide the floating text when hovering buttons inside each slide (so it doesn’t get in the way)
The First Hurdle: Cursor Trail Jumping or Sticking
At first, I tried updating the cursor-following text using transform: translate(...)
inside mousemove
, and it seemed okay. But it felt jumpy, and sometimes the text would just snap to the corner or get stuck.
After a bit of testing, I realised the issue was that I was mixing transform
with left/top
positioning. That doesn’t play well when you’re trying to animate smoothly using requestAnimationFrame
.
The Fix: Left & Top + Easing Transition
To get that smooth “trailing” or “wave” motion, I switched to updating left
and top
with easing. That way, the text glides behind the mouse rather than sticking to it like glue.
This made a big difference. Now the text follows the cursor in a fluid way – not jerky, not laggy, just smooth.
floatX += (mouseX - floatX) * 0.1;
floatY += (mouseY - floatY) * 0.1;
Next Issue: Hovering Over Buttons
Each slide had a button in the bottom-right corner (like “Book Now”). But when you hovered over that button, the floating “Next”/”Previous” text would still be there — not ideal for usability or design.
So I added a simple fix: detect when the user is hovering the button (or the caption area), and hide the floating text during that time.
$(document).on('mouseenter', '.v-pageHead__caption', function () {
hoveringButton = true;
$('.floating-nav').css('opacity', 0);
});
$(document).on('mouseleave', '.v-pageHead__caption', function () {
hoveringButton = false;
});
Now, when you’re over the button, the cursor tail disappears. Clean and and tidy.
Keeping It Clean: Only Run If Slider Is Active
One more thing I wanted to avoid was unnecessary code running on pages where there was only one slide — or no slider at all.
So I wrapped everything inside a conditional check like this:
if ($('.v-pageHead__slide', '.v-pageHead__slider').length > 1) {
// Only run this whole block if more than 1 slide
}
That way, no Swiper is initialised unless needed, and no extra listeners or animations are running in the background.
Finally, This was a fun little UX tweak — a bit fiddly at times, but the end result feels smooth and adds a nice touch. It’s the kind of detail that makes a site feel that bit more alive.
If you’re using Swiper and fancy something a bit cooler than the usual arrows, give it a try! And if you want a peek at the code, just give me a shout here.
Leave a Reply