Saksham Kushwaha

Avatar Group

Component

About

A flexible avatar group with overflow counts and stacked layouts.

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds Avatar Group to your project and fits it to your theme.

Code

How Avatar Group is used: the demo's code. The component's own source comes with a free account.

Usage.tsx

import { Avatar as BlobzAvatarImage, type AvatarProps as BlobzAvatarImageProps } from "@blobz/react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "cn";
import { BlobAvatarGroup, BlobAvatarGroupCount, BlobAvatarGroupItem } from "@/components/ui/avatar-group";

export const DEMO_PEOPLE = {
  gagandeepKang: "Gagandeep Kang",
  janakiAmmal: "Janaki Ammal",
  kalpanaChawla: "Kalpana Chawla",
  rajReddy: "Raj Reddy",
  srinivasaRamanujan: "Srinivasa Ramanujan",
  vikramSarabhai: "Vikram Sarabhai",
} as const;

const WHITESPACE_PATTERN = /\s+/;

export const getFirstName = (name: string): string =>
  name.trim().split(WHITESPACE_PATTERN)[0] ?? name;

const blobAvatarVariants = cva(
	"relative inline-flex shrink-0 overflow-hidden align-middle ring-1 ring-foreground/5",
	{
		defaultVariants: {
			frame: "rounded",
			size: "default",
			variant: "default",
		},
		variants: {
			frame: {
				circle: "rounded-full",
				rounded: "rounded-lg",
				square: "rounded-none",
			},
			size: {
				default: "size-10",
				lg: "size-12",
				sm: "size-8",
				xl: "size-16",
			},
			variant: {
				default: "bg-muted",
				elevated: "bg-muted shadow-md ring-1 ring-border/80",
				outline: "bg-background ring-1 ring-border",
			},
		},
	}
);

export interface BlobAvatarProps
	extends Omit<BlobzAvatarImageProps, "className" | "frame" | "size">,
		VariantProps<typeof blobAvatarVariants> {
	readonly className?: string;
	readonly imageClassName?: string;
}

export function BlobAvatar({
	className,
	frame = "rounded",
	imageClassName,
	size = "default",
	variant = "default",
	...imageProps
}: BlobAvatarProps) {
	return (
		<span
			className={cn(blobAvatarVariants({ frame, size, variant }), className)}
			data-frame={frame}
			data-size={size}
			data-slot="blob-avatar"
			data-variant={variant}
		>
			<BlobzAvatarImage
				{...imageProps}
				className={cn("block size-full object-cover", imageClassName)}
				frame={frame ?? "rounded"}
				size="100%"
			/>
		</span>
	);
}

export { blobAvatarVariants };

const TEAM = [
	{ id: "janaki", name: getFirstName(DEMO_PEOPLE.janakiAmmal) },
	{ id: "vikram", name: getFirstName(DEMO_PEOPLE.vikramSarabhai) },
	{ id: "kalpana", name: getFirstName(DEMO_PEOPLE.kalpanaChawla) },
] as const;

const BLUE_PALETTE = ["#dff4ff", "#38bdf8"] as const;

export function AvatarGroupExample() {
	return (
		<BlobAvatarGroup aria-label="Project team">
			{TEAM.map((member) => (
				<BlobAvatarGroupItem key={member.id}>
					<BlobAvatar alt="" name={member.name} palette={BLUE_PALETTE} />
				</BlobAvatarGroupItem>
			))}
			<BlobAvatarGroupCount count={4} />
		</BlobAvatarGroup>
	);
}

export default AvatarGroupExample;

Dependencies

More by Saksham Kushwaha

View all
  • User Table

    User Table

  • Group Chat

    Group Chat

  • Avatar Team List

    Avatar Team List

  • Avatar Select

    Avatar Select

  • Avatar Account Menu

    Avatar Account Menu

  • Presence Avatar

    Presence Avatar

  • Avatar Social Proof

    Avatar Social Proof

  • Avatar Chip

    Avatar Chip