Skip to content

Spotlight Card

Light cards under the pointer, with a shared glow across neighboring cards.

import { SpotlightCard, SpotlightGrid } from '@youj/motion/interactions'

Installation & usage

npm i @youj/motion

For an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.

Use it for a grid of choices people scan with the pointer: integrations, templates, plans. The light tells them where they are, and the shared glow along neighboring edges makes the grid feel like one surface. Keep it off dense dashboards, where every card is read rather than chosen. SpotlightCard is the Spotlight effect with a card look, so reach for the effect when you need your own look.

SpotlightGrid lays out its cards and shares one light across them. It's a CSS grid, so add your own columns and gaps.

import { SpotlightCard, SpotlightGrid } from '@youj/motion/interactions'

export function Integrations({ items }: { items: Integration[] }) {
  return (
    <SpotlightGrid className="grid-cols-3 gap-3">
      {items.map((item) => (
        <SpotlightCard key={item.slug}>
          <a href={`/integrations/${item.slug}`} className="block h-full rounded-xl p-4">
            {item.name}
          </a>
        </SpotlightCard>
      ))}
    </SpotlightGrid>
  )
}

A card brings the look: a 12px radius, a hairline border and the surface color. Pass className to change any of it. When the whole card is one link or button, put the control inside the card and let it fill the card, as the demo does, so the card and its target are the same size.

Reference

Propsradius, children, radius… (4)

Props

SpotlightCard

SpotlightCard props
PropType
radiusnumber

Radius of the light in px when used outside a SpotlightGroup.

default 260

260
childrenReactNode–

Other props pass through to the card's div.

SpotlightGrid

SpotlightGrid props
PropType
radiusnumber

Radius of the light in px.

default 260

260
childrenReactNode–

Other props pass through to the grid's div.

KeyboardTab through the grid

Keyboard

Tab through the grid in the demo. Keyboard focus parks the light at the center of the focused card, and moving focus to the next card glides it across. Touch doesn't move the light.

MotionPointer, keyboard glide, glow in and out · reduced motion

Motion

Motion tokens
MomentTokens
Pointerthe light follows the pointer
no token

one write per animation frame

one write per animation frame
Keyboard glidethe light moves to the focused card
duration.slowease.standard

340ms · cubic-bezier(0.2, 0, 0, 1)

340mscubic-bezier(0.2, 0, 0, 1)
Glow in and outsurface glow and border glow, opacity
duration.slowease.standard

340ms · cubic-bezier(0.2, 0, 0, 1)

340mscubic-bezier(0.2, 0, 0, 1)

Reduced motion

No tracking and no glow. The hovered or focused card shows a static accent border instead.

Reduced motion

The light doesn't follow the pointer. The card under the pointer, or the one holding keyboard focus, shows a static accent border, so the grid still marks where the reader is, without movement.

AccessibilityKeyboard, ARIA, focus

Accessibility

  • The light's layers are aria-hidden, and the cards add no roles or tab stops. Put the link or button inside the card, and give it a visible focus ring.
  • Keyboard focus lights the focused card just as the pointer does, so the effect is never pointer-only.
  • The glow is decoration. Say what the card is, and whether it's installed or selected, in its content.