All Taste components
Micro-interactions
Like button
A like button where the heart pops, a ring of dots bursts out and the count ticks over.
liked · not liked · count
"use client";
/* globals.css
@keyframes heart-pop { 0% { transform: scale(1); } 30% { transform: scale(.72); } 65% { transform: scale(1.22); } 100% { transform: scale(1); } }
@keyframes burst { from { opacity: 1; transform: rotate(var(--r)) translateY(-7px) scale(1); } to { opacity: 0; transform: rotate(var(--r)) translateY(-18px) scale(.3); } }
*/
import { useState } from "react";
import { Heart } from "lucide-react";
import { cn } from "@/lib/utils";
export function LikeButton({ count = 127, liked: initial = false }: { count?: number; liked?: boolean }) {
const [liked, setLiked] = useState(initial);
const [burst, setBurst] = useState(0);
const shown = count + (liked ? 1 : 0) - (initial ? 1 : 0);
function toggle() {
if (!liked) setBurst((b) => b + 1);
setLiked(!liked);
}
return (
<button
type="button"
aria-pressed={liked}
aria-label="Like"
onClick={toggle}
className={cn(
"inline-flex h-10 items-center gap-2 rounded-full border pl-[11px] pr-3.5 text-sm font-medium transition active:scale-[.96] motion-reduce:transition-none",
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
liked ? "border-danger/35 bg-danger-soft text-danger" : "border-border bg-bg text-fg-muted hover:border-border-strong",
)}
>
<span className="relative grid size-5 place-items-center">
<Heart
key={burst}
className={cn("size-5", liked && "fill-current animate-[heart-pop_.45s_cubic-bezier(.34,1.56,.64,1)] motion-reduce:animate-none")}
/>
{liked && burst > 0 &&
[0, 1, 2, 3, 4, 5].map((i) => (
<span
key={burst + "-" + i}
aria-hidden
className={cn(
"absolute left-1/2 top-1/2 -m-0.5 size-1 rounded-full opacity-0 animate-[burst_.6s_cubic-bezier(.2,.7,.1,1)] motion-reduce:hidden",
i % 2 ? "bg-warning" : "bg-current",
)}
style={{ "--r": i * 60 + "deg" } as React.CSSProperties}
/>
))}
</span>
<span key={shown} className="tabular-nums animate-rise motion-reduce:animate-none">{shown}</span>
</button>
);
}
The code uses the Taste Tailwind preset. Make yours on the Taste page with Export my system.