Shimmer Button
ButtonsA primary button with a light sheen that sweeps across on hover. Self-contained — the effect is a CSS pseudo-element, no keyframes or dependencies.
"use client";
import * as React from "react";
import { cn } from "@/lib/utils";
export type ShimmerButtonProps = React.ComponentProps<"button">;
/**
* A primary button with a light sheen that sweeps across on hover.
* Self-contained: the effect is a `::before` pseudo-element, no keyframes.
*/
export function ShimmerButton({ className, children, ...props }: ShimmerButtonProps) {
return (
<button
data-slot="shimmer-button"
className={cn(
"group relative inline-flex h-11 items-center justify-center gap-2 overflow-hidden rounded-base bg-accent px-6 text-sm font-medium text-accent-fg shadow-sm outline-none transition-[transform,box-shadow] duration-150",
"hover:shadow-md active:translate-y-px",
"focus-visible:ring-2 focus-visible:ring-accent/60 focus-visible:ring-offset-2 focus-visible:ring-offset-background",
"disabled:pointer-events-none disabled:opacity-50",
"before:pointer-events-none before:absolute before:inset-0 before:-translate-x-full before:bg-linear-to-r before:from-transparent before:via-white/35 before:to-transparent before:transition-transform before:duration-700 before:ease-out hover:before:translate-x-full",
"[&_svg]:size-4 [&_svg]:shrink-0",
className,
)}
{...props}
>
<span className="relative z-10 inline-flex items-center gap-2">{children}</span>
</button>
);
}Overview
A primary call-to-action button with a light sheen that sweeps across on hover. It draws the eye to your most important action without being noisy.
How it works
The sheen is a single ::before pseudo-element — a horizontal gradient that's
translated off-screen and slides across on hover. There are no keyframes and
no dependencies beyond cn, so it's trivial to drop into any project.
Prefer one shimmer button per view. Like any motion accent, its impact comes from being the exception, not the rule.
Accessibility
It's a native <button>, so focus and keyboard activation work out of the box,
with a visible focus ring. The motion is hover-only and subtle, avoiding
distraction for users sensitive to movement.
Installation
npx shadcn@latest add https://ui.saumyarex.xyz/r/shimmer-button.json1. Install dependencies
npm install clsx tailwind-merge2. Copy the source into your project
"use client";
import * as React from "react";
import { cn } from "@/lib/utils";
export type ShimmerButtonProps = React.ComponentProps<"button">;
/**
* A primary button with a light sheen that sweeps across on hover.
* Self-contained: the effect is a `::before` pseudo-element, no keyframes.
*/
export function ShimmerButton({ className, children, ...props }: ShimmerButtonProps) {
return (
<button
data-slot="shimmer-button"
className={cn(
"group relative inline-flex h-11 items-center justify-center gap-2 overflow-hidden rounded-base bg-accent px-6 text-sm font-medium text-accent-fg shadow-sm outline-none transition-[transform,box-shadow] duration-150",
"hover:shadow-md active:translate-y-px",
"focus-visible:ring-2 focus-visible:ring-accent/60 focus-visible:ring-offset-2 focus-visible:ring-offset-background",
"disabled:pointer-events-none disabled:opacity-50",
"before:pointer-events-none before:absolute before:inset-0 before:-translate-x-full before:bg-linear-to-r before:from-transparent before:via-white/35 before:to-transparent before:transition-transform before:duration-700 before:ease-out hover:before:translate-x-full",
"[&_svg]:size-4 [&_svg]:shrink-0",
className,
)}
{...props}
>
<span className="relative z-10 inline-flex items-center gap-2">{children}</span>
</button>
);
}import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
/** Merge conditional class names and resolve Tailwind conflicts. */
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
...props | React.ComponentProps<"button"> | — | All native button attributes are forwarded; children render above the sheen. |