/

Spotlight Cards: One Gradient, Twenty Times the Cost

The most-copied pointer effect of the last two years, the two CSS variables that make it free, and the three ways it gets expensive.

Serafim Korablev
Serafim Korablev
@korablev

The spotlight is the most-copied pointer effect of the last two years, and for once the popularity is deserved: a soft light that follows the cursor across a dark surface makes a static card feel alive for the cost of one radial gradient. It is also the effect most often shipped at twenty times its necessary cost.

29 public components on 21st have "spotlight" in the name.

The components

Spotlight Card by Hossain Jahed is the most-bookmarked card in the entire catalogue and the reference implementation of the pattern. Card Spotlight by Manu Arora is the same idea with a revealed radial gradient, and Spotlight by the same author is the section-level beam rather than a card treatment.

Feature Spotlight by Jatin Yadav applies it to a feature block, and Spotlight Button by wisedev is the navigation variant.

Apple Spotlight by Samit Kapoor is a different thing entirely despite the name: a search overlay rather than a light effect, and the command palette guide covers that pattern.

The cheap implementation

Two CSS custom properties for the pointer position, one radial-gradient that reads them, and a ::before layer that fades in on hover. No JavaScript animation, no re-render, no library.

css

The pointer handler does one thing: set --x and --y. That is a style write, not a React state update, which is the difference between an effect that costs nothing and one that re-renders a card on every mouse move.

The three ways it gets expensive

State per card. Storing the pointer position in React state re-renders the component on every frame of every movement. Write to the CSS variable directly on the element instead.

A listener per card. Twenty cards is twenty handlers. Track on the grid container and pass the coordinates down, as the card guide recommends for every pointer-tracked treatment.

Stacking it with everything else. Spotlight plus a blurred backdrop plus an animated gradient border, times twenty, is a compositing bill. Pick one treatment per card and keep the full stack for the one that is featured.

Where it works and where it does not

It works on dark surfaces, because the effect is added light. On a white card a spotlight is either invisible or a grey smudge, and the usual response - increasing the opacity - produces the smudge.

It does not exist on touch, so it is an enhancement rather than a signal. If the cards need to look interactive on a phone, that has to come from something else: a border, a chevron, a press state.

And it is motion in the sense that matters: under prefers-reduced-motion: reduce, skip the tracking and leave the card static.

Where else to look

The honest list, because the answer is not always us:

SourceBest forTrade-off
Two CSS variables and a radial gradientThe whole effect, at essentially no costYou write the pointer handler
MotionSprings and easing on the followA runtime for a gradient
21stCards, sections, feature blocks and navigation variantsQuality varies by author, so preview before you take it

Taking one

Every component page has a live preview and the code. Installing goes through the shadcn CLI against our registry:

bash

That key comes from your 21st account, and installs require a membership. Set API_KEY_21ST once in your shell and the command works for anything in the catalogue.

Browse card components →

Frequently asked

How do you build a spotlight card cheaply?
Two CSS custom properties for the pointer position, a radial gradient that reads them on a pseudo-element, and a pointer handler whose only job is to set those variables. That is a style write rather than a React state update, which is the difference between free and a re-render per frame.
Why is my grid of spotlight cards slow?
Three usual causes: pointer position stored in React state, one listener per card, and the effect stacked with a blurred backdrop and an animated border. Track on the grid container, write to CSS variables directly, and keep the full treatment for the featured card.
Does the spotlight effect work on light backgrounds?
Poorly. The effect is added light, so on a white card it is either invisible or, once the opacity is raised to compensate, a grey smudge. It belongs on dark surfaces.
What should a spotlight card do on touch?
Look interactive some other way, since the effect does not exist without a pointer. A border, a chevron or a press state carries the affordance, and under prefers-reduced-motion the tracking should be skipped entirely.

Published

Aug 21, 2026

Read time

3 min

Tags

GuideEffectsReactPerformance

Share