composed · Composed pattern
AvatarGroup
@devalok/shilp-sutra/composed/avatar-groupView in Storybook Hand-curated previews ship in rolling waves. See it live in Storybook →
Reference
Props
users: AvatarUser[] (REQUIRED) — { name: string, image?: string | null, ring?: AvatarRing }
max: number (default: 4, overflow shows "+N" badge)
size: "xs" | "sm" | "md" | "lg" | "xl"
showTooltip: boolean (default: true)
borderColor: "surface-base" | "surface-raised" (default: "surface-raised") — overlap border color
onOverflowClick: () => void — makes the "+N" badge interactive (button)
renderAvatar: (user: AvatarUser, index: number) => ReactNode — custom avatar render
expandDirection: "left" | "right" (default: "right") — direction group expands on hover
expandAmount: "compact" | "default" | "wide" (default: "default") — how far group spreads
AvatarUser Type
name: string (REQUIRED)
image?: string | null
ring?: "none" | "lead" | "admin" | "client" — role ring per user in group
indicator?: "lead" | "admin" | ReactNode — small dot indicator at top-right of avatar
Defaults
size="md", max=4, showTooltip=true, borderColor="surface-raised", expandDirection="right", expandAmount="default"
Example
<AvatarGroup
users={[
{ name: 'Alice', image: '/alice.jpg', ring: 'lead' },
{ name: 'Bob', ring: 'admin' },
]}
max={3}
size="md"
borderColor="surface-base"
onOverflowClick={() => setShowAll(true)}
/>
Composability
- Built on ui/Avatar — each slot is an Avatar with overlap + border + optional Tooltip.
- Wraps TooltipProvider internally — don't add another.
- renderAvatar escape hatch for custom shapes. Wrapper handles overlap/border positioning; your renderer sets size + shape.
- borderColor must match the surface the group sits on (
surface-raisedon Card,surface-baseon page bg). Mismatch = visible seam. - Overflow: +N badge with optional
onOverflowClick→ pair with a Popover/Sheet for "show all members". - Per-user
ring(lead/admin/client) surfaces Avatar's ring semantic at group level — use for role/presence hints.
Gotchas
- Wraps TooltipProvider internally — no need to add one yourself
- Users beyond
maxare collapsed into a "+N" overflow badge - Missing
imagefalls back to initials derived fromname - Hover expand animation uses CSS
group-hover— parent must not clip overflow borderColorshould match the surface the group sits on (surface-baseon page bg,surface-raisedon cards)renderAvatarwrapper is positioning-only — passsizedirectly to your Avatar (do NOT useclassName="h-full w-full")
Changes
v0.29.0
- Added
indicatorprop on AvatarUser:"lead"(warning dot) |"admin"(accent dot) | ReactNode (custom indicator) — animated dot at the top-right corner of each avatar
v0.22.3
- Fixed
renderAvatarwrapper no longer clips consumer Avatar content (removed overflow-hidden, border, and size classes from wrapper) - Fixed Removed redundant text-size classes from wrapper — Avatar handles font scaling internally
v0.21.0
- Added
xsandxlsize variants - Added
borderColorprop for overlap border matching surface context - Added
onOverflowClickprop making the overflow badge an interactive button - Added
renderAvatarprop for custom per-avatar rendering - Added
AvatarUser.ringfield for per-user role rings in groups
v0.1.0
- Added Initial release