Avatar

User avatar component with image support, initials fallback, multiple sizes, square and circular shapes, and an AvatarGroup for overlapping stacks.

Preview

Basic avatar with initials

import { Avatar } from '@/registry/ui-kit/tailwind-avatar/react'

function Example() {
  return <Avatar initials="JD" />
}

Sizes

import { Avatar } from '@/registry/ui-kit/tailwind-avatar/react'

function Example() {
  return (
    <div className="flex items-center gap-3">
      <Avatar initials="XS" size="xs" />
      <Avatar initials="SM" size="sm" />
      <Avatar initials="MD" size="md" />
      <Avatar initials="LG" size="lg" />
      <Avatar initials="XL" size="xl" />
    </div>
  )
}

Avatar group

import { Avatar, AvatarGroup } from '@/registry/ui-kit/tailwind-avatar/react'

function Example() {
  return (
    <AvatarGroup>
      <Avatar initials="JD" />
      <Avatar initials="AS" />
      <Avatar initials="MK" />
      <Avatar initials="RL" />
    </AvatarGroup>
  )
}

Component API

PropDefaultDescription
srcImage URL for the avatar. Falls back to initials when not provided.
alt""Alt text for the avatar image.
initialsOne or two characters shown when no image src is provided.
size"md"Size of the avatar.
squarefalseUse rounded-lg instead of rounded-full.
className""Additional CSS classes.
AvatarGroupWraps multiple Avatar components with overlapping negative-margin layout.

Source Code

"use client";

import { forwardRef } from "react";

/* ── Size mapping ── */

const sizeStyles = {
  xs: "h-6 w-6 text-xs",
  sm: "h-8 w-8 text-xs",
  md: "h-10 w-10 text-sm",
  lg: "h-12 w-12 text-base",
  xl: "h-16 w-16 text-lg",
};

type AvatarSize = keyof typeof sizeStyles;

/* ── Avatar ── */

interface AvatarProps extends React.HTMLAttributes<HTMLSpanElement> {
  src?: string;
  alt?: string;
  initials?: string;
  size?: AvatarSize;
  square?: boolean;
  className?: string;
}

const Avatar = forwardRef<HTMLSpanElement, AvatarProps>(
  ({ src, alt = "", initials, size = "md", square = false, className = "", ...props }, ref) => {
    const sizeClass = sizeStyles[size];
    const shapeClass = square ? "rounded-lg" : "rounded-full";

    return (
      <span
        ref={ref}
        className={`relative inline-flex shrink-0 items-center justify-center overflow-hidden ${sizeClass} ${shapeClass} ${className}`}
        {...props}
      >
        {src ? (
          <img
            src={src}
            alt={alt}
            className={`h-full w-full object-cover ${shapeClass}`}
          />
        ) : (
          <span className={`flex h-full w-full items-center justify-center bg-zinc-100 font-medium text-zinc-600 dark:bg-zinc-800 dark:text-zinc-300 ${shapeClass}`}>
            {initials}
          </span>
        )}
      </span>
    );
  }
);
Avatar.displayName = "Avatar";

/* ── AvatarGroup ── */

interface AvatarGroupProps extends React.HTMLAttributes<HTMLDivElement> {
  className?: string;
  children: React.ReactNode;
}

const AvatarGroup = forwardRef<HTMLDivElement, AvatarGroupProps>(
  ({ className = "", children, ...props }, ref) => {
    return (
      <div
        ref={ref}
        className={`flex -space-x-2 ${className}`}
        {...props}
      >
        {children}
      </div>
    );
  }
);
AvatarGroup.displayName = "AvatarGroup";

export { Avatar, AvatarGroup };
export type { AvatarSize };
export default Avatar;