Avatar Group
godui/avatar-groupFreeComponent
Overlapping avatars that fan apart on hover, with a +N overflow chip.
Install it
npx shadcn@latest add https://godui.design/r/avatar-group.jsonSource
1"use client";23import { motion, useReducedMotion } from "framer-motion";4import * as React from "react";56export type Avatar = {7 src?: string;8 alt?: string;9 /** Fallback initials shown when no `src` (or it fails to load). */10 fallback?: string;11 href?: string;12};1314export type AvatarGroupSize = "sm" | "md" | "lg";1516export type AvatarGroupProps = React.HTMLAttributes<HTMLDivElement> & {17 avatars: Avatar[];18 /** Maximum avatars shown before collapsing into a `+N` chip. */19 max?: number;20 size?: AvatarGroupSize;21 /** Spread the stack apart on hover. */22 spreadOnHover?: boolean;23};2425const sizeClasses: Record<AvatarGroupSize, string> = {26 sm: "size-8 text-xs",27 md: "size-10 text-sm",28 lg: "size-12 text-base",29};3031const overlap: Record<AvatarGroupSize, number> = {32 sm: 10,33 md: 12,34 lg: 14,35};3637function Initials({ avatar }: { avatar: Avatar }) {38 const [errored, setErrored] = React.useState(false);39 const label = avatar.fallback ?? avatar.alt?.slice(0, 2).toUpperCase() ?? "?";40 if (avatar.src && !errored) {41 return (42 <img43 src={avatar.src}44 alt={avatar.alt ?? ""}45 onError={() => setErrored(true)}46 className="size-full object-cover"47 />48 );49 }50 return (51 <span className="flex size-full items-center justify-center bg-muted font-medium text-muted-foreground">52 {label}53 </span>54 );55}5657const AvatarGroup = React.forwardRef<HTMLDivElement, AvatarGroupProps>(58 (59 {60 avatars,61 max = 4,62 size = "md",63 spreadOnHover = true,64 className,65 ...props66 },67 ref,68 ) => {69 const reduceMotion = useReducedMotion();70 const visible = avatars.slice(0, max);71 const overflow = avatars.length - visible.length;72 const margin = -overlap[size];7374 return (75 <motion.div76 ref={ref}77 initial="rest"78 whileHover={spreadOnHover && !reduceMotion ? "spread" : undefined}79 animate="rest"80 className={`group flex items-center ${className ?? ""}`}81 {...(props as React.ComponentProps<typeof motion.div>)}82 >83 {visible.map((avatar, i) => {84 const ringClasses =85 "ring-2 ring-background rounded-full overflow-hidden bg-background shadow-sm";86 const inner = (87 // biome-ignore lint/correctness/useJsxKeyInIterable: keyed on the wrapper element returned below88 <motion.div89 variants={{90 rest: { marginLeft: i === 0 ? 0 : margin, y: 0 },91// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from godui
All 105 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | godui | Components | Free | 1 dep | |
| Agent Flowagent-flow | godui | Components | Free | 1 dep | |
| Agent Timelineagent-timeline | godui | Components | Free | 1 dep | |
| Animated Beamanimated-beam | godui | Components | Free | 1 dep | |
| Animated Testimonialsanimated-testimonials | godui | Components | Free | 1 dep | |
| Animated Tooltipanimated-tooltip | godui | Components | Free | 1 dep | |
| App Showcaseapp-showcase | godui | Components | Free | 1 dep | |
| Aurora Textaurora-text | godui | Components | Free | no deps |
