Mischief

69 / Scenes

Spotlight Card

A card that catches a light following the pointer, and can light every card in its grid from the same pointer at once.

Sketch

Free

One project, all components.

Studio

$12

Unlimited projects and themes.

Workshop

$40

Everything, plus review calls.

Installation

Copy the source into your project, or keep it behind a package.

npx shadcn@latest add Tinkerers-Labs/mischief-ui/spotlight-card
import { SpotlightCard } from "mischief-ui/spotlight-card"

Or paste it in yourself. The source imports the shared cn helper from @/lib/utils, so point that at your own copy.

registry/default/spotlight-card/spotlight-card.tsx
"use client" import * as React from "react"import { cn } from "@/lib/utils" export type SpotlightCardProps = React.HTMLAttributes<HTMLDivElement> & {  /** A theme custom property or CSS colour for the light. */  color?: string  /** Radius of the light in pixels. */  size?: number  /** Lights every card in a group at once when they share a parent. */  followGroup?: boolean} 

Usage

export function Plans({ plans }) {
  return (
    <div className="grid gap-3 sm:grid-cols-3">
      {plans.map((plan) => (
        <SpotlightCard key={plan.name} followGroup className="p-5">
          <p>{plan.name}</p>
        </SpotlightCard>
      ))}
    </div>
  )
}

Nothing re-renders

The pointer position is written to custom properties on the element itself, not to React state. Moving across a grid of twelve of these updates twelve style properties and renders nothing, which is the difference between a smooth grid and a grid that stutters on a laptop.

It also means the card is an ordinary element. Wrap it in a link, put a form in it, or give it your own background, and none of that interferes with the light.

One lamp over a grid

With followGroup on, a card that receives the pointer writes the position to every sibling spotlight card as well. Each one converts the same page coordinate against its own rectangle, so the light lands where it would if a single lamp were held above the whole grid rather than one lamp per card.

The effect is quiet and worth the trouble: cards near the pointer glow slightly even though the pointer is not on them, which is what a real light does.

API

colorstringA theme custom property or a CSS colour for the light. Defaults to "--primary".
sizenumberRadius of the light in pixels. Defaults to 320.
followGroupbooleanLights every sibling spotlight card from the same pointer, so a grid reads as one surface under one lamp.

Accessibility

The light is decoration drawn behind the content and never carries meaning, so nothing is announced. It fades rather than jumps, and that fade is removed under reduced motion. Because the effect is driven by the pointer rather than by a timer, there is nothing moving for a reader who is not moving.