CSS hover effects can make a simple button feel much more interactive without adding JavaScript.
For this component, I wanted to create a button with a neon light that appears to travel around the border when the user hovers over it. The final effect uses only HTML and CSS.
What We're Building
The button starts with a clean light appearance. On hover:
- The button face becomes dark
- A cyan, blue, purple, and magenta light rotates around the border
- A soft neon glow appears around the button
- The arrow moves slightly to the right
- The button lifts a few pixels
I also added keyboard focus styles and reduced-motion support.
HTML
The structure is intentionally small:
<div class="cr-neon-orbit-demo">
<button class="cr-neon-orbit-btn" type="button">
<span
class="cr-neon-orbit-btn__track"
aria-hidden="true">
<span class="cr-neon-orbit-btn__runner"></span>
</span>
<span
class="cr-neon-orbit-btn__face"
aria-hidden="true">
</span>
<span class="cr-neon-orbit-btn__content">
<span class="cr-neon-orbit-btn__label">
Get Started
</span>
<span
class="cr-neon-orbit-btn__arrow"
aria-hidden="true">
→
</span>
</span>
</button>
</div>
The track contains the animated light source, while the face creates the actual button surface.
Creating the Neon Orbit
The main trick is a conic-gradient() placed inside an element larger than the button.
.cr-neon-orbit-btn__runner {
position: absolute;
width: 320px;
height: 320px;
top: 50%;
left: 50%;
margin-top: -160px;
margin-left: -160px;
background: conic-gradient(
from 0deg,
transparent 0deg,
transparent 255deg,
#22d3ee 280deg,
#38bdf8 295deg,
#8b5cf6 315deg,
#d946ef 332deg,
transparent 350deg,
transparent 360deg
);
animation: cr-neon-orbit-spin 2.2s linear infinite;
}
Most of the gradient is transparent. Only a small section contains the neon colors.
When the large gradient rotates behind the rounded button face, that colored section appears to travel around the edge.
Rotation Animation
The animation itself is very simple:
@keyframes cr-neon-orbit-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
The visual complexity comes mostly from the gradient rather than from complicated animation logic.
Hover Interaction
On hover, the neon track becomes visible:
.cr-neon-orbit-btn:hover
.cr-neon-orbit-btn__track {
opacity: 1;
box-shadow:
0 0 12px rgba(34, 211, 238, 0.35),
0 0 22px rgba(139, 92, 246, 0.28),
0 0 32px rgba(217, 70, 239, 0.18);
}
The inner face also shrinks slightly and changes from light to dark:
.cr-neon-orbit-btn:hover
.cr-neon-orbit-btn__face {
inset: 3px;
background: #05070c;
box-shadow:
inset 0 0 0 1px rgba(255, 255, 255, 0.035),
0 12px 30px rgba(0, 0, 0, 0.4);
}
That small inset exposes the animated neon layer underneath.
Arrow Movement
A subtle movement gives the button another layer of feedback:
.cr-neon-orbit-btn:hover
.cr-neon-orbit-btn__arrow {
transform: translateX(5px);
}
It's a small detail, but it makes the interaction feel more responsive.
Keyboard Accessibility
Hover shouldn't be the only visible interaction state.
The button also includes a keyboard focus indicator:
.cr-neon-orbit-btn:focus-visible {
outline: 3px solid #22d3ee;
outline-offset: 7px;
}
Reduced Motion
For users who prefer reduced motion, the rotation can be disabled:
@media (prefers-reduced-motion: reduce) {
.cr-neon-orbit-btn,
.cr-neon-orbit-btn__face,
.cr-neon-orbit-btn__content,
.cr-neon-orbit-btn__arrow {
transition: none;
}
.cr-neon-orbit-btn__runner {
animation: none;
}
}
Live Demo
I also published the component on CodePen so you can test the hover effect directly and experiment with the code:
Full Source & Tutorial
The complete component, including the full CSS and a live preview, is available on CodeRipple:
Neon Orbit CSS Button Hover Effect
The component uses HTML and CSS only, so no JavaScript is required.
If you customize it, try changing the conic-gradient() colors and animation duration. A few small changes can produce a completely different orbit effect.
Top comments (0)