Skip to content

Glare Hover

A band of light that sweeps across a card or an image when the pointer or keyboard focus reaches it.

Motionv0.1.0experimentalWCAG 2.2 AAView spec

Optional, and kept apart.

Nothing here is included in a project unless you add it, and the plain component it builds on is unchanged. This effect is decoration: it is hidden from screen readers, stands still for visitors who prefer reduced motion, and can be paused. Use Still on a preview to see that version.

Pro plan

Hover or focus this card to see the glare.

import { GlareHover } from "@rdloom/react";

// The default glare is a soft tint of the action colour, so it shows on a light card.
export default function GlareHoverBasicExample() {
  return (
    <div className="flex w-full justify-center py-6">
      <GlareHover
        tabIndex={0}
        className="w-80 rounded-[var(--rd-radius-overlay)] border border-[var(--rd-color-border-default)] bg-[var(--rd-color-surface-default)] p-6 outline-none focus-visible:ring-2 focus-visible:ring-[var(--rd-color-focus-ring)]"
      >
        <h3 className="text-lg font-semibold">Pro plan</h3>
        <p className="mt-1 text-sm text-[var(--rd-color-text-muted)]">Hover or focus this card to see the glare.</p>
      </GlareHover>
    </div>
  );
}

Installation

npx rdloom add glare-hover

Copies the source into src/components/rdloom. Edit it freely: rdloom upgrade merges later versions into your changes.

It also adds rdloom-motion.css next to your tokens and imports it from the tokens file, once: no setup, and no inline styles. The plain components you already use are untouched.

Use another registry client
npx shadcn@latest add https://rdloom.vimalbhatt.com/r/glare-hover.json

Works, but without upgrade tracking, and you import the motion CSS yourself.

Usage

import { GlareHover } from "@rdloom/react";

<div className="flex w-full justify-center py-6">
  <GlareHover
    tabIndex={0}
    className="w-80 rounded-[var(--rd-radius-overlay)] border border-[var(--rd-color-border-default)] bg-[var(--rd-color-surface-default)] p-6 outline-none focus-visible:ring-2 focus-visible:ring-[var(--rd-color-focus-ring)]"
  >
    <h3 className="text-lg font-semibold">Pro plan</h3>
    <p className="mt-1 text-sm text-[var(--rd-color-text-muted)]">Hover or focus this card to see the glare.</p>
  </GlareHover>
</div>

On image

Green highlands under a cloudy sunrise with a winding road
import { GlareHover } from "@rdloom/react";

// On a photo or a dark surface, set the glare to white at low strength.
export default function GlareHoverOnImageExample() {
  return (
    <div className="flex w-full justify-center py-4">
      <GlareHover angle={-30} duration={0.9} color="rgb(255 255 255 / 0.45)" className="h-56 w-full max-w-md rounded-[var(--rd-radius-overlay)]">
        <img
          src="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?auto=format&fit=crop&w=1200&q=80"
          alt="Green highlands under a cloudy sunrise with a winding road"
          className="size-full object-cover"
        />
      </GlareHover>
    </div>
  );
}

API Reference

Defined by the spec. Components also accept the props of the React Aria component they wrap.

PropTypeDefault
childrenrequired

The content to sweep across.

nodenone
angle

Tilt of the band in degrees.

number-20
duration

Seconds for one sweep.

number0.7
color

Colour of the glare, any CSS colour. Defaults to a soft tint of the action colour, which shows on light and dark surfaces. Use white at low strength on a dark card.

stringnone
isPaused

Stops the effect and shows it still.

booleanfalse

Accessibility

Role group, WCAG 2.2 AA. Tested with axe and keyboard tests; screen reader checks are in the audit checklist.

Keyboard

Not interactive.

Screen readers announce

  • Read as ordinary content: the glare is not announced

What your code must do

  • The glare is decoration: aria-hidden and never blocks the pointer
  • It sweeps once on hover and once on focus-within, so keyboard users see the same effect, and it is not a way to show state
  • Off for reduced motion, inside rdm-still and with isPaused
  • The glare is a faint tint, so the text or image underneath keeps its contrast
  • In forced-colors (high contrast) mode the band is removed

Guidelines

Use it when

  • Product images and feature cards
  • A hover accent on a photo

Avoid it when

  • Text the reader must keep reading while the band crosses it

Don't

  • Using the glare as the only sign that something is clickable
  • Strong, opaque glare colours

Design tokens

The semantic tokens this component uses. Change them once and every component follows; see Design tokens.

  • --rd-radius-overlay
  • --rd-color-border-default