Shine Button
FreeA call-to-action button with a soft light sweep on hover and keyboard focus.
- #button
- #hover
- #gradient
- #cta
Code
ShineButton.tsx
import type { AnchorHTMLAttributes, ButtonHTMLAttributes, ReactNode } from "react";
type ShineButtonProps =
| ({ href: string; children: ReactNode } & AnchorHTMLAttributes<HTMLAnchorElement>)
| ({ href?: undefined; children: ReactNode } & ButtonHTMLAttributes<HTMLButtonElement>);
const base =
"group relative inline-flex items-center justify-center overflow-hidden rounded-full bg-gradient-to-r from-violet-600 via-blue-600 to-teal-600 px-7 py-3 text-sm font-semibold text-white shadow-lg shadow-blue-600/25 transition-transform duration-200 hover:-translate-y-0.5 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-blue-500 active:translate-y-0 motion-reduce:transition-none motion-reduce:hover:translate-y-0";
function Shine() {
return (
<span
aria-hidden="true"
className="pointer-events-none absolute inset-y-0 -left-1/2 w-1/3 -skew-x-12 bg-white/40 blur-sm transition-transform duration-700 ease-out group-hover:translate-x-[400%] group-focus-visible:translate-x-[400%] motion-reduce:hidden"
/>
);
}
export default function ShineButton(props: ShineButtonProps) {
if (props.href !== undefined) {
const { children, className = "", ...rest } = props;
return (
<a className={`${base} ${className}`} {...rest}>
<Shine />
<span className="relative">{children}</span>
</a>
);
}
const { children, className = "", type = "button", ...rest } = props;
return (
<button type={type} className={`${base} ${className}`} {...rest}>
<Shine />
<span className="relative">{children}</span>
</button>
);
}
export function Preview() {
return (
<div className="flex flex-wrap items-center gap-4">
<ShineButton>Get started</ShineButton>
<ShineButton href="#pricing">See pricing</ShineButton>
</div>
);
}
About Shine Button
A primary button for the one action that matters on a screen. The light sweep draws the eye without moving anything else on the page.
Features
- A diagonal highlight sweeps across the gradient on hover and on keyboard focus.
- Pure CSS animation on
transform, so it stays on the GPU and never shifts layout. - Works as a
<button>or, withhref, as a link.
Accessibility
- Native
<button>/<a>semantics; no ARIA needed. - Visible focus ring that also triggers the sweep, so keyboard users get the same feedback.
- The sweep is turned off under
prefers-reduced-motion: reduce.