Badge Pop Hover Effect
Original · freeBadges and pills that pop and change colour 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-badge-pop.json"use client";
import { useId, useState } from "react";
type Badge = {
label: string;
count?: number;
base: string;
hover: string;
ring: string;
dot: string;
};
const badges: Badge[] = [
{
label: "New",
base: "border-emerald-200 bg-emerald-50 text-emerald-700 dark:border-emerald-500/30 dark:bg-emerald-500/10 dark:text-emerald-300",
hover:
"hover:border-emerald-500 hover:bg-emerald-600 hover:text-white dark:hover:bg-emerald-500 dark:hover:text-white dark:hover:border-emerald-400",
ring: "focus-visible:ring-emerald-500/50",
dot: "bg-emerald-500 group-hover/badge:bg-white",
},
{
label: "Trending",
count: 24,
base: "border-rose-200 bg-rose-50 text-rose-700 dark:border-rose-500/30 dark:bg-rose-500/10 dark:text-rose-300",
hover:
"hover:border-rose-500 hover:bg-rose-600 hover:text-white dark:hover:bg-rose-500 dark:hover:text-white dark:hover:border-rose-400",
ring: "focus-visible:ring-rose-500/50",
dot: "bg-rose-500 group-hover/badge:bg-white",
},
{
label: "Beta",
base: "border-amber-200 bg-amber-50 text-amber-700 dark:border-amber-500/30 dark:bg-amber-500/10 dark:text-amber-300",
hover:
"hover:border-amber-500 hover:bg-amber-500 hover:text-white dark:hover:bg-amber-500 dark:hover:text-white dark:hover:border-amber-400",
ring: "focus-visible:ring-amber-500/50",
dot: "bg-amber-500 group-hover/badge:bg-white",
},
{
label: "Pro",
base: "border-violet-200 bg-violet-50 text-violet-700 dark:border-violet-500/30 dark:bg-violet-500/10 dark:text-violet-300",
hover:
"hover:border-violet-500 hover:bg-violet-600 hover:text-white dark:hover:bg-violet-500 dark:hover:text-white dark:hover:border-violet-400",
ring: "focus-visible:ring-violet-500/50",
dot: "bg-violet-500 group-hover/badge:bg-white",
},
{
label: "Stable",
count: 8,
base: "border-sky-200 bg-sky-50 text-sky-700 dark:border-sky-500/30 dark:bg-sky-500/10 dark:text-sky-300",
hover:
"hover:border-sky-500 hover:bg-sky-600 hover:text-white dark:hover:bg-sky-500 dark:hover:text-white dark:hover:border-sky-400",
ring: "focus-visible:ring-sky-500/50",
dot: "bg-sky-500 group-hover/badge:bg-white",
},
{
label: "Featured",
base: "border-indigo-200 bg-indigo-50 text-indigo-700 dark:border-indigo-500/30 dark:bg-indigo-500/10 dark:text-indigo-300",
hover:
"hover:border-indigo-500 hover:bg-indigo-600 hover:text-white dark:hover:bg-indigo-500 dark:hover:text-white dark:hover:border-indigo-400",
ring: "focus-visible:ring-indigo-500/50",
dot: "bg-indigo-500 group-hover/badge:bg-white",
},
];
const filters = [
"Design",
"Engineering",
"Product",
"Research",
"Marketing",
"Support",
"Finance",
"Operations",
];
export default function HoverBadgePop() {
const groupId = useId();
const [active, setActive] = useState<Set<string>>(new Set(["Design", "Product"]));
const toggle = (name: string) => {
setActive((prev) => {
const next = new Set(prev);
if (next.has(name)) next.delete(name);
else next.add(name);
return next;
});
};
return (
<section className="relative w-full bg-white px-6 py-20 text-slate-900 dark:bg-slate-950 dark:text-slate-100 sm:py-24">
<style>{`
@keyframes hbp-pop-in {
0% { transform: scale(0.6); opacity: 0; }
70% { transform: scale(1.08); opacity: 1; }
100% { transform: scale(1); opacity: 1; }
}
.hbp-pop-in { animation: hbp-pop-in 240ms cubic-bezier(0.34, 1.56, 0.64, 1) both; }
@media (prefers-reduced-motion: reduce) {
.hbp-pop-in { animation: none; }
.hbp-badge, .hbp-badge * { transition: none !important; }
}
`}</style>
<div className="mx-auto max-w-4xl">
<div className="mb-12 text-center">
<span className="inline-block rounded-full border border-slate-200 bg-slate-50 px-3 py-1 text-xs font-medium uppercase tracking-wider text-slate-500 dark:border-slate-800 dark:bg-slate-900 dark:text-slate-400">
Interactive
</span>
<h2 className="mt-4 text-3xl font-semibold tracking-tight sm:text-4xl">
Badges that pop on hover
</h2>
<p className="mx-auto mt-3 max-w-xl text-base text-slate-600 dark:text-slate-400">
Hover or focus any pill. It scales up and shifts to a bolder colour with a smooth,
spring-like lift.
</p>
</div>
{/* Status badges */}
<div className="mb-14">
<h3 className="mb-4 text-sm font-semibold text-slate-500 dark:text-slate-400">
Status labels
</h3>
<div className="flex flex-wrap gap-3">
{badges.map((b) => (
<a
key={b.label}
href="#"
onClick={(e) => e.preventDefault()}
className={`hbp-badge group/badge inline-flex items-center gap-2 rounded-full border px-4 py-1.5 text-sm font-medium shadow-sm outline-none transition-all duration-200 ease-out hover:-translate-y-0.5 hover:scale-105 hover:shadow-md focus-visible:-translate-y-0.5 focus-visible:scale-105 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:focus-visible:ring-offset-slate-950 ${b.base} ${b.hover} ${b.ring}`}
>
<span
className={`h-1.5 w-1.5 rounded-full transition-colors duration-200 ${b.dot}`}
aria-hidden="true"
/>
{b.label}
{typeof b.count === "number" && (
<span className="tabular-nums opacity-70 transition-opacity duration-200 group-hover/badge:opacity-100">
{b.count}
</span>
)}
</a>
))}
</div>
</div>
{/* Selectable filter chips */}
<div>
<h3 className="mb-4 text-sm font-semibold text-slate-500 dark:text-slate-400">
Toggle filters
<span className="ml-2 font-normal text-slate-400 dark:text-slate-500">
({active.size} selected)
</span>
</h3>
<div role="group" aria-label="Team filters" className="flex flex-wrap gap-2.5">
{filters.map((name) => {
const on = active.has(name);
return (
<button
key={name}
type="button"
aria-pressed={on}
onClick={() => toggle(name)}
className={`hbp-badge group/chip inline-flex items-center gap-1.5 rounded-full border px-3.5 py-1.5 text-sm font-medium outline-none transition-all duration-200 ease-out hover:-translate-y-0.5 hover:scale-105 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-indigo-500/50 focus-visible:ring-offset-white dark:focus-visible:ring-offset-slate-950 ${
on
? "border-indigo-500 bg-indigo-600 text-white shadow-md shadow-indigo-500/20 hover:bg-indigo-500 dark:border-indigo-400 dark:bg-indigo-500 dark:hover:bg-indigo-400"
: "border-slate-200 bg-white text-slate-600 shadow-sm hover:border-indigo-300 hover:bg-indigo-50 hover:text-indigo-700 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-300 dark:hover:border-indigo-500/50 dark:hover:bg-indigo-500/10 dark:hover:text-indigo-300"
}`}
>
<span
key={`${groupId}-${name}-${on}`}
className={`hbp-pop-in flex h-4 w-4 items-center justify-center rounded-full text-[10px] ${
on
? "bg-white/25 text-white"
: "bg-slate-100 text-slate-400 dark:bg-slate-800 dark:text-slate-500"
}`}
aria-hidden="true"
>
{on ? (
<svg
viewBox="0 0 12 12"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="h-2.5 w-2.5"
>
<path d="M2.5 6.5 5 9l4.5-5" />
</svg>
) : (
<svg
viewBox="0 0 12 12"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
className="h-2.5 w-2.5"
>
<path d="M6 2.5v7M2.5 6h7" />
</svg>
)}
</span>
{name}
</button>
);
})}
</div>
</div>
</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 Fill Hover Effect
OriginalButtons with a colour fill that sweeps across 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.

