Avatar Group
Overlapping stack of avatars with automatic “+N” overflow — perfect for showing team members or participants.

JD
MK
Web preview — components render natively on iOS & Android
import { Avatar } from "@/components/ui/avatar";
import { AvatarGroup } from "@/components/ui/avatar-group";
export function TeamStack() {
return (
<AvatarGroup>
<Avatar src="https://github.com/anishlp7.png" fallback="AN" />
<Avatar fallback="JD" />
<Avatar fallback="MK" />
</AvatarGroup>
);
}Installation#
npx @aniui/cli add avatar-groupUsage#
app/index.tsx
import { Avatar } from "@/components/ui/avatar";
import { AvatarGroup } from "@/components/ui/avatar-group";
export function TeamStack() {
return (
<AvatarGroup>
<Avatar src="https://github.com/anishlp7.png" fallback="AN" />
<Avatar fallback="JD" />
<Avatar fallback="MK" />
</AvatarGroup>
);
}Overflow#
Avatars beyond max (default 4) collapse into a “+N” counter.
AN
JD
MK
+3
Web preview — components render natively on iOS & Android
// Only the first `max` avatars render; the rest collapse into "+N"
<AvatarGroup max={3}>
<Avatar fallback="AN" />
<Avatar fallback="JD" />
<Avatar fallback="MK" />
<Avatar fallback="SR" />
<Avatar fallback="TW" />
<Avatar fallback="PB" />
</AvatarGroup>
// Renders 3 avatars followed by a "+3" indicatorSpacing#
Control how tightly the avatars overlap.
AN
JD
MK
AN
JD
MK
AN
JD
MK
Web preview — components render natively on iOS & Android
<AvatarGroup spacing="sm">{/* tight overlap */}</AvatarGroup>
<AvatarGroup spacing="md">{/* default overlap */}</AvatarGroup>
<AvatarGroup spacing="lg">{/* deep overlap */}</AvatarGroup>Props#
PropTypeDefault
maxnumber4spacing"sm" | "md" | "lg""md"childrenReactNode—classNamestring—Also accepts all View props from React Native. Children are typically Avatar components.
Accessibility#
- Each child
Avatarkeeps its own accessibility semantics. - The “+N” overflow counter is rendered as text and read by screen readers.
Source#
components/ui/avatar-group.tsx
import React from "react";
import { View, Text } from "react-native";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
// spacing is applied as a negative left margin per item (not -space-x-*) because
// neither NativeWind nor Uniwind supports Tailwind's sibling-selector space utilities.
const avatarGroupItemVariants = cva("rounded-full border-2 border-background", {
variants: {
spacing: {
sm: "-ml-2",
md: "-ml-3",
lg: "-ml-4",
},
},
defaultVariants: {
spacing: "md",
},
});
export interface AvatarGroupProps
extends React.ComponentPropsWithoutRef<typeof View>,
VariantProps<typeof avatarGroupItemVariants> {
className?: string;
max?: number;
children?: React.ReactNode;
}
export function AvatarGroup({ spacing, max = 4, className, children, ...props }: AvatarGroupProps) {
const items = React.Children.toArray(children);
const visible = items.slice(0, max);
const overflow = items.length - visible.length;
return (
<View className={cn("flex-row items-center", className)} {...props}>
{visible.map((child, index) => (
<View
key={index}
className={cn(avatarGroupItemVariants({ spacing }), index === 0 && "ml-0")}
>
{child}
</View>
))}
{overflow > 0 && (
<View
className={cn(
avatarGroupItemVariants({ spacing }),
"h-10 w-10 items-center justify-center bg-muted",
visible.length === 0 && "ml-0"
)}
>
<Text className="text-sm font-medium text-muted-foreground">+{overflow}</Text>
</View>
)}
</View>
);
}