Button Fill Hover Effect
Original · freeButtons with a colour fill that sweeps across on hover.
Copy prompt gives Claude Code, Cursor or v0 a ready-to-paste prompt that recreates this exact component.
npx shadcn@latest add https://webinnoventix.com/r/hover-button-fill.json"use client";
import { useState } from "react";
type Variant = {
id: string;
label: string;
hint: string;
base: string;
fill: string;
fillText: string;
span: string;
ring: string;
};
const VARIANTS: Variant[] = [
{
id: "ltr",
label: "Deploy to production",
hint: "Sweep · left → right",
base:
"border-indigo-300 text-indigo-700 dark:border-indigo-500/50 dark:text-indigo-300",
fill: "bg-indigo-600 dark:bg-indigo-500",
fillText: "group-hover:text-white group-focus-visible:text-white",
span: "origin-left scale-x-0 group-hover:scale-x-100 group-focus-visible:scale-x-100",
ring: "focus-visible:ring-indigo-500/60",
},
{
id: "rtl",
label: "Roll back release",
hint: "Sweep · right → left",
base:
"border-rose-300 text-rose-700 dark:border-rose-500/50 dark:text-rose-300",
fill: "bg-rose-600 dark:bg-rose-500",
fillText: "group-hover:text-white group-focus-visible:text-white",
span: "origin-right scale-x-0 group-hover:scale-x-100 group-focus-visible:scale-x-100",
ring: "focus-visible:ring-rose-500/60",
},
{
id: "btt",
label: "Publish article",
hint: "Sweep · bottom → top",
base:
"border-emerald-300 text-emerald-700 dark:border-emerald-500/50 dark:text-emerald-300",
fill: "bg-emerald-600 dark:bg-emerald-500",
fillText: "group-hover:text-white group-focus-visible:text-white",
span: "origin-bottom scale-y-0 group-hover:scale-y-100 group-focus-visible:scale-y-100",
ring: "focus-visible:ring-emerald-500/60",
},
{
id: "ttb",
label: "Download report",
hint: "Sweep · top → bottom",
base:
"border-sky-300 text-sky-700 dark:border-sky-500/50 dark:text-sky-300",
fill: "bg-sky-600 dark:bg-sky-500",
fillText: "group-hover:text-white group-focus-visible:text-white",
span: "origin-top scale-y-0 group-hover:scale-y-100 group-focus-visible:scale-y-100",
ring: "focus-visible:ring-sky-500/60",
},
{
id: "center",
label: "Start free trial",
hint: "Sweep · from centre",
base:
"border-violet-300 text-violet-700 dark:border-violet-500/50 dark:text-violet-300",
fill: "bg-violet-600 dark:bg-violet-500",
fillText: "group-hover:text-white group-focus-visible:text-white",
span: "origin-center scale-x-0 group-hover:scale-x-100 group-focus-visible:scale-x-100",
ring: "focus-visible:ring-violet-500/60",
},
{
id: "amber",
label: "Upgrade plan",
hint: "Sweep · left → right",
base:
"border-amber-300 text-amber-700 dark:border-amber-500/50 dark:text-amber-300",
fill: "bg-amber-500 dark:bg-amber-400",
fillText:
"group-hover:text-amber-950 group-focus-visible:text-amber-950",
span: "origin-left scale-x-0 group-hover:scale-x-100 group-focus-visible:scale-x-100",
ring: "focus-visible:ring-amber-500/60",
},
];
function FillButton({ variant }: { variant: Variant }) {
const [clicked, setClicked] = useState(false);
return (
<button
type="button"
onClick={() => {
setClicked(true);
window.setTimeout(() => setClicked(false), 900);
}}
aria-pressed={clicked}
className={[
"group relative inline-flex w-full items-center justify-center overflow-hidden",
"rounded-xl border-2 bg-white px-6 py-3.5 text-sm font-semibold tracking-tight",
"outline-none transition-[transform,box-shadow] duration-200 ease-out",
"hover:-translate-y-0.5 active:translate-y-0",
"focus-visible:ring-4 focus-visible:ring-offset-2",
"focus-visible:ring-offset-white dark:focus-visible:ring-offset-slate-950",
"dark:bg-slate-900",
variant.base,
variant.ring,
].join(" ")}
>
<span
aria-hidden="true"
className={[
"absolute inset-0 z-0 transform-gpu transition-transform duration-500",
"ease-[cubic-bezier(0.22,1,0.36,1)] motion-reduce:transition-none",
"motion-reduce:group-hover:scale-100",
variant.fill,
variant.span,
].join(" ")}
/>
<span
className={[
"relative z-10 flex items-center gap-2 transition-colors duration-300",
"motion-reduce:transition-none",
variant.fillText,
].join(" ")}
>
<span
aria-hidden="true"
className={
"hbf-tick h-2 w-2 rounded-full bg-current opacity-70 " +
(clicked ? "hbf-pulse" : "")
}
/>
{clicked ? "Confirmed" : variant.label}
</span>
</button>
);
}
export default function HoverButtonFill() {
return (
<section className="relative w-full bg-slate-50 px-6 py-20 dark:bg-slate-950 sm:px-8 lg:py-28">
<style>{`
@keyframes hbf-pulse-kf {
0% { transform: scale(1); opacity: 0.7; }
40% { transform: scale(2.4); opacity: 0; }
100% { transform: scale(1); opacity: 0.7; }
}
.hbf-pulse { animation: hbf-pulse-kf 0.9s ease-out; }
@media (prefers-reduced-motion: reduce) {
.hbf-pulse { animation: none; }
}
`}</style>
<div className="mx-auto max-w-4xl">
<div className="mb-12 max-w-2xl">
<span className="inline-flex items-center gap-2 rounded-full border border-slate-200 bg-white px-3 py-1 text-xs font-medium text-slate-600 dark:border-slate-800 dark:bg-slate-900 dark:text-slate-400">
<span className="h-1.5 w-1.5 rounded-full bg-indigo-500" />
Hover interaction
</span>
<h2 className="mt-4 text-3xl font-semibold tracking-tight text-slate-900 dark:text-white sm:text-4xl">
Colour-fill buttons
</h2>
<p className="mt-3 text-base leading-relaxed text-slate-600 dark:text-slate-400">
The fill sweeps in on hover and focus, from any direction. Keyboard
focus triggers the same motion, and it collapses gracefully for
reduced-motion users. Click to confirm.
</p>
</div>
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
{VARIANTS.map((variant) => (
<div key={variant.id} className="flex flex-col gap-2">
<FillButton variant={variant} />
<span className="pl-1 text-xs font-medium text-slate-400 dark:text-slate-500">
{variant.hint}
</span>
</div>
))}
</div>
<p className="mt-10 text-xs text-slate-400 dark:text-slate-600">
Tab through the buttons — every fill animation runs on{" "}
<code className="rounded bg-slate-200 px-1 py-0.5 text-slate-600 dark:bg-slate-800 dark:text-slate-400">
:focus-visible
</code>{" "}
too, not hover alone.
</p>
</div>
</section>
);
}Dependencies
Licence
Built by Web Innoventix. Free for personal and commercial use, no attribution required.
Built by Web Innoventix
Need a custom interface, a full website, or SEO that gets you cited by AI? We design, build and rank it end to end.
Get a free quoteSimilar components
Browse all →
Card Lift Hover Effect
OriginalA card that lifts with a growing shadow on hover.

Card Glow Hover Effect
OriginalA card with a coloured glow that blooms on hover.

Card Border Draw Hover Effect
OriginalA card whose border draws itself in on hover.

Card Gradient Shift Hover Effect
OriginalA card whose gradient background shifts on hover.

Card Tilt Hover Effect
OriginalA card that tilts in 3D toward the cursor on hover.

Card Spotlight Hover Effect
OriginalA card with a cursor-following radial spotlight.

Link Underline Hover Effect
OriginalAnimated link underline effects: grow, slide and centre-out.

Link Slide Hover Effect
OriginalLinks whose label slides up to a duplicate on hover.

Button Shine Hover Effect
OriginalButtons with a diagonal shine sweep on hover.
Icon Fill Hover Effect
OriginalIcon buttons whose icon and background fill on hover.
Icon Bounce Hover Effect
OriginalIcons that bounce or spin playfully on hover.

List Highlight Hover Effect
OriginalA list where the hovered row gets a sliding highlight and arrow.

