Avatar Group
A visually interactive avatar group with hover effects and tooltips, allowing users to easily view and highlight avatars with smooth animations.
Preview
JD
SS
AW
EJ
Installation
Install dependencies
# Install Shadcn Avatar component
npx shadcn@latest add avatar
Create the component file
mkdir -p components/shsfui/avatar && touch components/shsfui/avatar/avatar-group.tsx
Add the component code
Open the newly created file and paste the following code:
"use client";
import * as React from "react";
import {
Avatar,
AvatarImage,
AvatarFallback,
} from "@/components/ui/avatar";
import { cn } from "@/utils/cn";
type AvatarItemType = {
src: string;
alt: string;
initials: string;
};
type AvatarGroupProps = {
avatars?: AvatarItemType[];
maxDisplay?: number;
showIndicator?: boolean;
className?: string;
};
export const DEFAULT_AVATARS: AvatarItemType[] = [
{
src: "https://randomuser.me/api/portraits/men/32.jpg",
alt: "John Doe",
initials: "JD",
},
{
src: "https://randomuser.me/api/portraits/women/44.jpg",
alt: "Sarah Smith",
initials: "SS",
},
{
src: "https://randomuser.me/api/portraits/men/91.jpg",
alt: "Alex Wong",
initials: "AW",
},
{
src: "https://randomuser.me/api/portraits/women/17.jpg",
alt: "Emma Johnson",
initials: "EJ",
},
];
const AvatarGroup = React.forwardRef<HTMLDivElement, AvatarGroupProps>(
(props, ref) => {
const {
avatars = DEFAULT_AVATARS,
maxDisplay = avatars.length,
showIndicator = false,
className,
} = props;
const displayAvatars = React.useMemo(
() => avatars.slice(0, maxDisplay),
[avatars, maxDisplay]
);
const remainingCount = avatars.length - maxDisplay;
return (
<div
ref={ref}
className={cn(
"bg-background flex items-center justify-center rounded-full border p-1",
className
)}
>
<div className="flex items-center relative">
{displayAvatars.map((avatar, index) => (
<div
key={index}
className={cn("relative hover:z-10", index > 0 && "-ml-2")}
>
<Avatar className="transition-all duration-300 hover:scale-105 hover:-translate-y-1 hover:shadow-lg border-2 border-background">
<AvatarImage src={avatar.src} alt={avatar.alt} />
<AvatarFallback>{avatar.initials}</AvatarFallback>
</Avatar>
{showIndicator && (
<span className="absolute bottom-0 right-0 block h-2 w-2 rounded-full bg-green-500 ring-2 ring-background" />
)}
</div>
))}
{remainingCount > 0 && (
<div className={cn("relative hover:z-10", "-ml-2")}>
<Avatar className="transition-all duration-300 hover:scale-105 hover:-translate-y-1 hover:shadow-lg border-2 border-background bg-muted">
<AvatarFallback>+{remainingCount}</AvatarFallback>
</Avatar>
</div>
)}
</div>
</div>
);
}
);
AvatarGroup.displayName = "AvatarGroup";
export AvatarGroup;