Wraps any content so a diagonal band of light sweeps across it on hover or keyboard focus, in white for images and dark surfaces or a soft shadow for light ones.
import { GlareHover } from "@/components/ballmac/glare-hover"
function poster(a: string, b: string, label: string) {
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="320" height="420"><defs><linearGradient id="g" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="${a}"/><stop offset="1" stop-color="${b}"/></linearGradient></defs><rect width="320" height="420" fill="url(#g)"/><circle cx="230" cy="110" r="52" fill="rgba(255,255,255,.35)"/><path d="M0 330 L90 230 L160 300 L230 210 L320 320 V420 H0Z" fill="rgba(0,0,0,.28)"/></svg>`
return { src: `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`, label }
}
const posters = [poster("#6366f1", "#22d3ee", "Aurora"), poster("#f97316", "#db2777", "Sunset"), poster("#10b981", "#0ea5e9", "Lagoon")]
export default function GlareHoverDemo() {
return (
<div className="grid w-full max-w-lg grid-cols-3 gap-3">
{posters.map((p) => (
<GlareHover key={p.label} className="rounded-xl border shadow-sm" tabIndex={0}>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img src={p.src} alt={p.label} className="aspect-[3/4] w-full object-cover" />
</GlareHover>
))}
</div>
)
}Installation
$ pnpm dlx shadcn@latest add @ballmac/glare-hoverAdd the Ballmac items it builds on.
$ pnpm dlx shadcn@latest add @ballmac/motion-presetsCopy the source into your project.
components/ballmac/glare-hover.tsx// Ballmac UI: Glare Hover. https://ui.ballmac.com/components/glare-hover "use client" import * as React from "react" import { cn } from "@/lib/utils" import { useReducedMotionSafe } from "@/lib/ballmac/motion" type GlareHoverProps = React.ComponentProps<"div"> & { /** Tilt of the band of light, in degrees. */ angle?: number /** Milliseconds the sweep takes. */ duration?: number /** Brightness of the glare, from 0 to 1. */ intensity?: number /** "light" sweeps white light, good over images and dark surfaces. "dark" sweeps a soft shadow, good on light surfaces. */ tone?: "light" | "dark" } function GlareHover({ angle = 18, duration = 800, intensity = 0.55, tone = "light", className, children, style, ...props }: GlareHoverProps) { const reduce = useReducedMotionSafe() const color = tone === "light" ? `rgb(255 255 255 / ${intensity})` : `color-mix(in oklab, var(--foreground) ${Math.round(intensity * 22)}%, transparent)` return ( <div data-slot="glare-hover" className={cn("group/glare relative isolate overflow-hidden", className)} style={{ ...style, ["--glare-ms" as string]: `${duration}ms` } as React.CSSProperties} {...props} > {children} {!reduce && ( <span aria-hidden="true" className="pointer-events-none absolute inset-0 z-10 overflow-hidden rounded-[inherit]"> <span className="absolute -inset-y-[40%] start-0 w-[45%] -translate-x-[130%] rtl:translate-x-[130%] transition-none group-focus-within/glare:translate-x-[300%] group-focus-within/glare:transition-transform group-focus-within/glare:duration-[var(--glare-ms)] group-focus-within/glare:ease-out group-hover/glare:translate-x-[300%] group-hover/glare:transition-transform group-hover/glare:duration-[var(--glare-ms)] group-hover/glare:ease-out rtl:group-focus-within/glare:-translate-x-[300%] rtl:group-hover/glare:-translate-x-[300%]" style={{ background: `linear-gradient(90deg, transparent, ${color} 50%, transparent)`, transform: `skewX(${-angle}deg)`, mixBlendMode: tone === "light" ? "overlay" : "normal" }} /> </span> )} </div> ) } export { GlareHover, type GlareHoverProps }Update the import paths to match your project setup.
Usage
import { GlareHover } from "@/components/ballmac/glare-hover"The full example is in the Code tab above.
Examples
Light and dark tone
Light glare
For images and dark surfaces.
Dark glare
A soft shadow band for light cards.
import { GlareHover } from "@/components/ballmac/glare-hover"
export default function GlareHoverTones() {
return (
<div className="grid w-full max-w-md gap-3 sm:grid-cols-2">
<GlareHover tone="light" intensity={0.7} className="rounded-xl bg-neutral-900 p-6 text-white" tabIndex={0}>
<p className="text-sm font-semibold">Light glare</p>
<p className="mt-1 text-xs text-neutral-300">For images and dark surfaces.</p>
</GlareHover>
<GlareHover tone="dark" intensity={0.8} className="rounded-xl border bg-card p-6" tabIndex={0}>
<p className="text-sm font-semibold">Dark glare</p>
<p className="mt-1 text-xs text-muted-foreground">A soft shadow band for light cards.</p>
</GlareHover>
</div>
)
}API reference
| Prop | Type | Default |
|---|---|---|
angleTilt of the band of light, in degrees. | number | 18 |
durationMilliseconds the sweep takes. | number | 800 |
intensityBrightness of the glare, from 0 to 1. | number | 0.55 |
tone"light" sweeps white light, good over images and dark surfaces. "dark" sweeps a soft shadow, good on light surfaces. | "light" | "dark" | "light" |
Also accepts the standard attributes of its root element.
Accessibility
| Key | Action |
|---|---|
| Focus | The sweep also plays when something inside gains keyboard focus |
| Screen readers | The glare is aria-hidden |
| Reduced motion | No glare is drawn |
Use with AI
<GlareHover angle duration intensity tone='light|dark'>anything</GlareHover>. The sweep runs once per hover and resets instantly when the pointer leaves. Pure CSS transitions; nothing renders on pointer move. With the shadcn MCP server set up (guide), ask your agent:
Add the Ballmac UI Glare Hover (@ballmac/glare-hover) to this project with the shadcn MCP, then use it where it fits.
Use it for
- Product images, posters and cards
- Anything that deserves a small touch of polish on hover
Not for
- Pointer-following lighting (magic-card or spotlight-card)
Registry JSON: https://ui.ballmac.com/r/glare-hover.json
Credits
Free to use in personal and commercial projects.
- npm
- None
Pairs well with
Tilt Card
A card that tilts in 3D toward the pointer with spring smoothing and a moving glare. TiltCardLayer children float at their own depth for parallax. Keyboard focus shows a gentle tilt.
Magic Card
A card with a two-color light that follows the pointer along its border, with an optional soft glow inside, driven by CSS variables so moving never re-renders, and a steady light on keyboard focus.
Card
A composable content surface with compact spacing, an action slot, and optional interactive feedback.
Animated Beam
An SVG beam that connects two elements with a curved path and sends a glowing gradient pulse along it. Follows layout changes, pauses off-screen, static under reduced motion.