Components
Avatar Group
A component for displaying multiple avatars with tooltips, borders, and spacing. Built on top of Avatar and Tooltip from shadcn UI.
CLCBGT+1
Installation
pnpm dlx shadcn@latest add https://rafay.sh/r/avatar-group.json
Usage
1import { AvatarGroup, type AvatarData } from "@/components/ui/avatar-group";1const avatars: AvatarData[] = [
2 { imageUrl: "/avatars/1.jpg", alt: "John Doe", fallback: "JD", tooltipLabel: "John Doe" },
3 { imageUrl: "/avatars/2.jpg", alt: "Jane Smith", fallback: "JS", tooltipLabel: "Jane Smith" },
4 { imageUrl: "/avatars/3.jpg", alt: "Alice Lee", fallback: "AL", tooltipLabel: "Alice Lee" },
5];
6
7<AvatarGroup
8 data={avatars}
9 size={12}
10 tooltip
11 spacing="tight"
12 max={3}
13 animate
14 translate
15/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
| data | AvatarData[] | [] | Array of avatar objects. Each object can include imageUrl, alt, fallback, and tooltipLabel. |
| size | number | undefined | Avatar size (1 = 4px) |
| tooltip | boolean | false | Show tooltip on hover. |
| tooltipSide | "top" | "right" | "bottom" | "left" | "top" | Tooltip position. |
| tooltipAlign | "center" | "start" | "end" | "center" | Tooltip alignment. |
| tooltipSideOffset | number | undefined | Offset of tooltip from avatar |
| tooltipAlignOffset | number | undefined | Offset for alignment |
| border | boolean | false | Add border around avatars. |
| borderWidth | number | undefined | Border width in pixels. |
| borderColor | string | undefined | Border color. |
| avatarClassName | string | "" | Custom class names for individual avatars. |
| max | number | undefined | Max number of avatars to display; remaining shown as +N. |
| spacing | "normal" | "tight" | "loose" | "tight" | Spacing between avatars. |
| spacingGap | number | undefined | Custom gap in pixels between avatars in px (overrides spacing). |
| animate | boolean | false | Enable hover scaling animation. |
| translate | boolean | false | Enable hover translate animation. |
Examples
Spacing
CLCBGTSM
example-component.tsx
1import { AvatarGroup } from "@/components/ui/avatar-group"
2
3export function AvatarGroupNormalSpacing() {
4 const data = [
5 {
6 imageUrl: "https://res.cloudinary.com/dyhub4ung/image/upload/v1765267940/yo_chico_yafmmp.jpg",
7 fallback: "CL",
8 tooltipLabel: "Chico Lachowski",
9 },
10 {
11 imageUrl: "https://res.cloudinary.com/dyhub4ung/image/upload/v1765267933/christian_bale_m4ectw.png",
12 fallback: "CB",
13 tooltipLabel: "Christian Bale",
14 },
15 {
16 imageUrl: "https://res.cloudinary.com/dyhub4ung/image/upload/v1765267980/pfp_guts_dowxcb.jpg",
17 fallback: "GT",
18 tooltipLabel: "Guts",
19 },
20 {
21 imageUrl: "https://res.cloudinary.com/dyhub4ung/image/upload/v1765267967/samurai_d0batp.jpg",
22 fallback: "SM",
23 tooltipLabel: "Samurai",
24 },
25 ];
26
27 return (
28 <div className="flex items-center justify-center">
29 <AvatarGroup
30 data={data}
31 size={12}
32 spacing="normal"
33 />
34 </div>
35 );
36}
37Tooltip
CLCBGTSM
example-component.tsx
1import { AvatarGroup } from "@/components/ui/avatar-group"
2
3export function AvatarGroupTooltip() {
4 const data = [
5 {
6 imageUrl: "https://res.cloudinary.com/dyhub4ung/image/upload/v1765267940/yo_chico_yafmmp.jpg",
7 fallback: "CL",
8 tooltipLabel: "Chico Lachowski",
9 },
10 {
11 imageUrl: "https://res.cloudinary.com/dyhub4ung/image/upload/v1765267933/christian_bale_m4ectw.png",
12 fallback: "CB",
13 tooltipLabel: "Christian Bale",
14 },
15 {
16 imageUrl: "https://res.cloudinary.com/dyhub4ung/image/upload/v1765267980/pfp_guts_dowxcb.jpg",
17 fallback: "GT",
18 tooltipLabel: "Guts",
19 },
20 {
21 imageUrl: "https://res.cloudinary.com/dyhub4ung/image/upload/v1765267967/samurai_d0batp.jpg",
22 fallback: "SM",
23 tooltipLabel: "Samurai",
24 },
25 ];
26
27 return (
28 <div className="flex items-center justify-center">
29 <AvatarGroup
30 data={data}
31 tooltip
32 size={12}
33 />
34 </div>
35 );
36}
37Border & Max
CLCBGT+1
example-component.tsx
1import { AvatarGroup } from "@/components/ui/avatar-group"
2
3export function AvatarGroupBorderAndMax() {
4 const data = [
5 {
6 imageUrl: "https://res.cloudinary.com/dyhub4ung/image/upload/v1765267940/yo_chico_yafmmp.jpg",
7 fallback: "CL",
8 tooltipLabel: "Chico Lachowski",
9 },
10 {
11 imageUrl: "https://res.cloudinary.com/dyhub4ung/image/upload/v1765267933/christian_bale_m4ectw.png",
12 fallback: "CB",
13 tooltipLabel: "Christian Bale",
14 },
15 {
16 imageUrl: "https://res.cloudinary.com/dyhub4ung/image/upload/v1765267980/pfp_guts_dowxcb.jpg",
17 fallback: "GT",
18 tooltipLabel: "Guts",
19 },
20 {
21 imageUrl: "https://res.cloudinary.com/dyhub4ung/image/upload/v1765267967/samurai_d0batp.jpg",
22 fallback: "SM",
23 tooltipLabel: "Samurai",
24 },
25 ];
26
27 return (
28 <div className="flex items-center justify-center">
29 <AvatarGroup
30 data={avatarGroupData}
31 tooltip
32 border
33 max={3}
34 borderWidth={2}
35 size={12}
36 />
37 </div>
38 );
39}
40Hover & Translate
CLCBGT+1
example-component.tsx
1import { AvatarGroup } from "@/components/ui/avatar-group"
2
3export function AvatarGroupBorderAndMax() {
4 const data = [
5 {
6 imageUrl: "https://res.cloudinary.com/dyhub4ung/image/upload/v1765267940/yo_chico_yafmmp.jpg",
7 fallback: "CL",
8 tooltipLabel: "Chico Lachowski",
9 },
10 {
11 imageUrl: "https://res.cloudinary.com/dyhub4ung/image/upload/v1765267933/christian_bale_m4ectw.png",
12 fallback: "CB",
13 tooltipLabel: "Christian Bale",
14 },
15 {
16 imageUrl: "https://res.cloudinary.com/dyhub4ung/image/upload/v1765267980/pfp_guts_dowxcb.jpg",
17 fallback: "GT",
18 tooltipLabel: "Guts",
19 },
20 {
21 imageUrl: "https://res.cloudinary.com/dyhub4ung/image/upload/v1765267967/samurai_d0batp.jpg",
22 fallback: "SM",
23 tooltipLabel: "Samurai",
24 },
25 ];
26
27 return (
28 <div className="flex items-center justify-center">
29 <AvatarGroup
30 data={avatarGroupData}
31 tooltip
32 max={3}
33 size={12}
34 animate
35 translate
36 />
37 </div>
38 );
39}
40