Components
Avatar Group
A component that arranges avatars with overlapping visual effects for displaying multiple users or items.
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { AvatarGroup } from "@/components/ui/avatar-group";
const avatars = [
{
name: "shadcn",
src: "https://github.com/shadcn.png",
fallback: "CN",
},
{
name: "Ethan Niser",
src: "https://github.com/ethanniser.png",
fallback: "EN",
},
{
name: "Guillermo Rauch",
src: "https://github.com/rauchg.png",
fallback: "GR",
},
{
name: "Lee Robinson",
src: "https://github.com/leerob.png",
fallback: "LR",
},
{
name: "Evil Rabbit",
src: "https://github.com/evilrabbit.png",
fallback: "ER",
},
{
name: "Tim Neutkens",
src: "https://github.com/timneutkens.png",
fallback: "TN",
},
];
export function AvatarGroupDemo() {
return (
<div className="flex flex-col gap-8">
<div className="flex flex-col gap-3">
<h3 className="font-medium text-sm">Avatar Group</h3>
<AvatarGroup>
{avatars.slice(0, 4).map((avatar, index) => (
<Avatar key={index}>
<AvatarImage src={avatar.src} alt={avatar.name} />
<AvatarFallback>{avatar.fallback}</AvatarFallback>
</Avatar>
))}
</AvatarGroup>
</div>
<div className="flex flex-col gap-3">
<h3 className="font-medium text-sm">
Avatar Group with overflow (max 4)
</h3>
<AvatarGroup max={4}>
{avatars.map((avatar, index) => (
<Avatar key={index}>
<AvatarImage src={avatar.src} alt={avatar.name} />
<AvatarFallback>{avatar.fallback}</AvatarFallback>
</Avatar>
))}
</AvatarGroup>
</div>
</div>
);
}Installation
CLI
npx shadcn@latest add "https://jolyui.dev/r/avatar-group"Manual
Install the following dependencies:
npm install @radix-ui/react-slot class-variance-authorityCopy and paste the following code into your project.
import { cn } from "@/lib/utils";
import {
AvatarGroup as AvatarGroupPrimitive,
type AvatarGroupProps,
} from "@jolyui/avatar-group";
// Re-export with cn utility integrated
export function AvatarGroup({
className,
...props
}: React.ComponentProps<typeof AvatarGroupPrimitive>) {
return <AvatarGroupPrimitive className={cn(className)} {...props} />;
}
export type { AvatarGroupProps };Layout
import { AvatarGroup } from "@/components/ui/avatar-group";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
<AvatarGroup>
<Avatar>
<AvatarImage src="/tony-hawk.png" />
<AvatarFallback>TH</AvatarFallback>
</Avatar>
<Avatar>
<AvatarImage src="/rodney-mullen.png" />
<AvatarFallback>RM</AvatarFallback>
</Avatar>
</AvatarGroup>Examples
With Truncation
Automatically truncate long lists and show overflow indicators with the max prop.
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { AvatarGroup } from "@/components/ui/avatar-group";
const avatars = [
{
name: "shadcn",
src: "https://github.com/shadcn.png",
fallback: "CN",
},
{
name: "Ethan Niser",
src: "https://github.com/ethanniser.png",
fallback: "EN",
},
{
name: "Guillermo Rauch",
src: "https://github.com/rauchg.png",
fallback: "GR",
},
{
name: "Lee Robinson",
src: "https://github.com/leerob.png",
fallback: "LR",
},
{
name: "Evil Rabbit",
src: "https://github.com/evilrabbit.png",
fallback: "ER",
},
{
name: "Tim Neutkens",
src: "https://github.com/timneutkens.png",
fallback: "TN",
},
{
name: "Delba de Oliveira",
src: "https://github.com/delbaoliveira.png",
fallback: "DO",
},
{
name: "Shu Ding",
src: "https://github.com/shuding.png",
fallback: "SD",
},
];
export function AvatarGroupTruncationDemo() {
return (
<div className="flex flex-col gap-6">
<div className="flex flex-col gap-3">
<h3 className="font-medium text-sm">Max 3 items</h3>
<AvatarGroup max={3}>
{avatars.map((avatar, index) => (
<Avatar key={index}>
<AvatarImage src={avatar.src} alt={avatar.name} />
<AvatarFallback>{avatar.fallback}</AvatarFallback>
</Avatar>
))}
</AvatarGroup>
</div>
<div className="flex flex-col gap-3">
<h3 className="font-medium text-sm">Max 5 items</h3>
<AvatarGroup max={5}>
{avatars.map((avatar, index) => (
<Avatar key={index}>
<AvatarImage src={avatar.src} alt={avatar.name} />
<AvatarFallback>{avatar.fallback}</AvatarFallback>
</Avatar>
))}
</AvatarGroup>
</div>
</div>
);
}With RTL
Support for right-to-left layouts and vertical RTL stacking.
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { AvatarGroup } from "@/components/ui/avatar-group";
const avatars = [
{
name: "shadcn",
src: "https://github.com/shadcn.png",
fallback: "CN",
},
{
name: "Ethan Niser",
src: "https://github.com/ethanniser.png",
fallback: "EN",
},
{
name: "Guillermo Rauch",
src: "https://github.com/rauchg.png",
fallback: "GR",
},
{
name: "Lee Robinson",
src: "https://github.com/leerob.png",
fallback: "LR",
},
];
export function AvatarGroupRtlDemo() {
return (
<div className="grid gap-6 md:grid-cols-2">
<div className="flex flex-col gap-3">
<h3 className="font-medium text-sm">RTL</h3>
<AvatarGroup dir="rtl">
{avatars.map((avatar, index) => (
<Avatar key={index}>
<AvatarImage src={avatar.src} alt={avatar.name} />
<AvatarFallback>{avatar.fallback}</AvatarFallback>
</Avatar>
))}
</AvatarGroup>
</div>
<div className="flex flex-col gap-3">
<h3 className="font-medium text-sm">Reverse RTL</h3>
<AvatarGroup dir="rtl" reverse>
{avatars.map((avatar, index) => (
<Avatar key={index}>
<AvatarImage src={avatar.src} alt={avatar.name} />
<AvatarFallback>{avatar.fallback}</AvatarFallback>
</Avatar>
))}
</AvatarGroup>
</div>
<div className="flex flex-col gap-3">
<h3 className="font-medium text-sm">Vertical RTL</h3>
<div className="flex justify-center">
<AvatarGroup orientation="vertical" dir="rtl">
{avatars.map((avatar, index) => (
<Avatar key={index}>
<AvatarImage src={avatar.src} alt={avatar.name} />
<AvatarFallback>{avatar.fallback}</AvatarFallback>
</Avatar>
))}
</AvatarGroup>
</div>
</div>
<div className="flex flex-col gap-3">
<h3 className="font-medium text-sm">Vertical reverse RTL</h3>
<div className="flex justify-center">
<AvatarGroup orientation="vertical" dir="rtl" reverse>
{avatars.map((avatar, index) => (
<Avatar key={index}>
<AvatarImage src={avatar.src} alt={avatar.name} />
<AvatarFallback>{avatar.fallback}</AvatarFallback>
</Avatar>
))}
</AvatarGroup>
</div>
</div>
</div>
);
}With Icons
Use the Avatar Group component with icons or other elements beyond avatars.
import { Bell, Heart, MessageCircle, Settings, Star, User } from "lucide-react";
import { AvatarGroup } from "@/components/ui/avatar-group";
const iconData = [
{ icon: User, color: "bg-blue-500" },
{ icon: Heart, color: "bg-red-500" },
{ icon: Star, color: "bg-yellow-500" },
{ icon: MessageCircle, color: "bg-green-500" },
{ icon: Settings, color: "bg-purple-500" },
{ icon: Bell, color: "bg-orange-500" },
];
export function AvatarGroupIconsDemo() {
return (
<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
<div className="flex flex-col gap-3">
<h3 className="font-medium text-sm">Icon Group</h3>
<AvatarGroup>
{iconData.slice(0, 4).map((item, index) => {
const IconComponent = item.icon;
return (
<div
key={index}
className={`flex size-10 items-center justify-center rounded-full text-white ${item.color}`}
>
<IconComponent size={16} />
</div>
);
})}
</AvatarGroup>
</div>
<div className="flex flex-col gap-3">
<h3 className="font-medium text-sm">Icon Group with Truncation</h3>
<AvatarGroup max={3}>
{iconData.map((item, index) => {
const IconComponent = item.icon;
return (
<div
key={index}
className={`flex size-10 items-center justify-center rounded-full text-white ${item.color}`}
>
<IconComponent size={16} />
</div>
);
})}
</AvatarGroup>
</div>
<div className="flex flex-col gap-3">
<h3 className="font-medium text-sm">Reverse Icon Group</h3>
<AvatarGroup reverse>
{iconData.slice(0, 4).map((item, index) => {
const IconComponent = item.icon;
return (
<div
key={index}
className={`flex size-10 items-center justify-center rounded-full text-white ${item.color}`}
>
<IconComponent size={16} />
</div>
);
})}
</AvatarGroup>
</div>
<div className="flex flex-col gap-3">
<h3 className="font-medium text-sm">Reverse with Truncation</h3>
<AvatarGroup reverse max={3}>
{iconData.map((item, index) => {
const IconComponent = item.icon;
return (
<div
key={index}
className={`flex size-10 items-center justify-center rounded-full text-white ${item.color}`}
>
<IconComponent size={16} />
</div>
);
})}
</AvatarGroup>
</div>
<div className="flex flex-col gap-3">
<h3 className="font-medium text-sm">Vertical Icon Group</h3>
<div className="flex justify-center">
<AvatarGroup orientation="vertical" size={32}>
{iconData.slice(0, 4).map((item, index) => {
const IconComponent = item.icon;
return (
<div
key={index}
className={`flex size-8 items-center justify-center rounded-full text-white ${item.color}`}
>
<IconComponent size={14} />
</div>
);
})}
</AvatarGroup>
</div>
</div>
<div className="flex flex-col gap-3">
<h3 className="font-medium text-sm">Vertical Reverse Icon Group</h3>
<div className="flex justify-center">
<AvatarGroup orientation="vertical" reverse size={32}>
{iconData.slice(0, 4).map((item, index) => {
const IconComponent = item.icon;
return (
<div
key={index}
className={`flex size-8 items-center justify-center rounded-full text-white ${item.color}`}
>
<IconComponent size={14} />
</div>
);
})}
</AvatarGroup>
</div>
</div>
</div>
);
}API Reference
AvatarGroup
The main avatar group container that handles layout and masking of child elements.
Prop
Type
| Data Attribute | Value |
|---|---|
[data-orientation] | "horizontal" | "vertical" |
How is this guide?