Shine Sweep Button
A narrow band of light glides across the button once when you hover or focus it.
Make a CSS-only shine sweep on a React button. The button has position: relative and overflow: hidden. Add a ::after pseudo-element covering the button with a 100-degree linear-gradient: transparent at 30%, white at 45% opacity at 50%, transparent at 70%. Rest it at transform: translateX(-120%). On :hover and :focus-visible, move it to translateX(120%) over 700ms with cubic-bezier(0.16, 1, 0.3, 1); when the pointer leaves, snap it back with transition: none so the sweep only plays forward. Animate transform only. Under prefers-reduced-motion, hide the sweep and use a slightly lighter background on hover. The label reads "Download the kit".
Source
'use client'
import s from './demo.module.css'
export default function ShineSweep({ labels }: { labels: Record<string, string> }) {
return (
<button type="button" className={s.button}>
{labels.cta}
</button>
)
}
.button {
position: relative;
overflow: hidden;
height: 52px;
padding: 0 28px;
border: 0;
border-radius: 12px;
background: var(--stage-accent);
color: var(--stage-accent-ink);
font: 600 var(--text-base) / 1 var(--font-body);
white-space: nowrap;
cursor: pointer;
}
.button::after {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(100deg, transparent 30%, var(--stage-sheen) 50%, transparent 70%);
transform: translateX(-120%);
pointer-events: none;
}
.button:hover::after,
.button:focus-visible::after {
transform: translateX(120%);
transition: transform 700ms var(--ease-out);
}
.button:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 3px; }
.button:active { transform: translateY(1px); }
@media (prefers-reduced-motion: reduce) {
.button::after { display: none; }
.button:hover { background: var(--stage-accent-hover); }
}