Light that follows the pointer
Move a radial highlight with CSS variables, not re-renders.
Sam Selikoff@samselikoffJust posted a new recipe: Spotlight! A subtle hover treatment with a radial gradient that follows your mouse. Uses Framer Motion to update the gradient's position outside of React's render cycle.
1 · Flat or lit
Move over the cards, or tap one to place the light.
Flat hover fillBad
:hover { background }SpotlightGood
radial-gradient at var(--x) var(--y)card.addEventListener("pointermove", (e) => {
const r = card.getBoundingClientRect();
card.style.setProperty("--x", `${e.clientX - r.left}px`);
card.style.setProperty("--y", `${e.clientY - r.top}px`);
});
.card::before {
background: radial-gradient(240px circle at var(--x) var(--y),
color-mix(in oklch, var(--fg) 10%, transparent), transparent 70%);
}
2 · Where the light moves
Sweep across each card and watch the counters.
Rebuild the cardBad
Nodes rebuilt
0Set a CSS variableGood
Nodes rebuilt
0Variable writes0Why it matters, pros and cons
Why it matters
A soft light under the pointer makes a card feel touchable, and a variable keeps it cheap.
Pros
- Two property writes per move; the gradient reads them, so no DOM work.
- Text, focus and selection inside the card are never rebuilt or lost.
- One shared rule lights every card, with no per-card state.
Cons
- Touch has no hover, so the light needs a tap or it never appears there.
- A gradient repaints on every move, so keep cards small and few.
- On a dense grid the effect turns to noise; use it on a handful of cards.