Avatar

Component

Clean Tailwind avatar components for user profiles, featuring initials, notification badges, and grouped layouts.

Install via CLI

Run this command to automatically add the component and its dependencies to your project.

npx @abhaysinghr516/business-wish add avatar
New to the CLI? Run npx @abhaysinghr516/business-wish init first to initialize your project.

Display user identities flawlessly with these Tailwind avatar components. Whether you are building a dashboard timeline or a Tailwind user profile dropdown, these avatars support image fallbacks, active status rings, and beautifully stacked group configurations.

Avatars combine perfectly with a Badge for activity status, and are frequently used within Dropdowns for account menus.

Avatar with Initials

A flat, cleanly spaced avatar sizing scale, removing inset shadows for a pure look.

import React from "react";
import { User } from "lucide-react";

interface AvatarProps {
  size?: "sm" | "md" | "lg";
  src?: string;
  alt?: string;
  initials?: string;
  className?: string;
}

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

const AvatarSizes: React.FC<AvatarProps> = ({
  src,
  alt = "User avatar",
  initials,
  className = "",
}) => {
  return (
    <div>
      <div className="mt-8 flex gap-6 items-end">
        {Object.keys(sizeClasses).map((sizeKey) => (
          <div key={sizeKey} className="text-center flex flex-col items-center">
            <h4 className="mb-3 text-[13px] font-medium text-neutral-500 dark:text-neutral-400">
              {sizeKey}
            </h4>
            <div
              className={`relative inline-flex items-center justify-center overflow-hidden 
              bg-neutral-100 dark:bg-neutral-800 text-neutral-600 dark:text-neutral-300
              rounded-full transition-colors duration-300
              ${sizeClasses[sizeKey as keyof typeof sizeClasses]} ${className}`}
            >
              {src ? (
                <img
                  src={src}
                  alt={alt}
                  className="w-full h-full object-cover"
                />
              ) : initials ? (
                <span className="font-medium tracking-tight">
                  {initials}
                </span>
              ) : (
                <User className="w-1/2 h-1/2 opacity-70" strokeWidth={2} />
              )}
            </div>
          </div>
        ))}
      </div>
    </div>
  );
};

export default AvatarSizes;

Avatar with Image

A simple, flat avatar utilizing soft neutral backgrounds when loading images.

import React from "react";

interface AvatarProps {
  size?: "sm" | "md" | "lg";
  src?: string;
  alt?: string;
  initials?: string;
  className?: string;
}

const AvatarWithImage: React.FC<AvatarProps> = ({
  src = "/pfp.jpg",
  alt = "User avatar",
  className = "",
}) => {
  return (
    <div
      className={`relative inline-flex items-center justify-center overflow-hidden 
      bg-neutral-100 dark:bg-neutral-800 
      rounded-full w-10 h-10 transition-colors duration-300 ${className}`}
    >
      <img src={src} alt={alt} className="w-full h-full object-cover" />
    </div>
  );
};

export default AvatarWithImage;

Avatar with Notification Badge

A sleek avatar featuring a seamlessly integrated top-right notification dot with a dark-mode optimized ring.

import React from "react";
import { User } from "lucide-react";

interface AvatarProps {
  size?: "sm" | "md" | "lg";
  src?: string;
  alt?: string;
  initials?: string;
  className?: string;
}

interface AvatarWithIndicatorProps extends AvatarProps {
  indicatorColor?: string;
}

const AvatarWithNotification: React.FC<AvatarWithIndicatorProps> = ({
  src,
  alt = "User avatar",
  initials,
  indicatorColor = "bg-red-500",
  className = "",
}) => {
  return (
    <div className="relative inline-block">
      <div
        className={`relative inline-flex items-center justify-center overflow-hidden 
        bg-neutral-100 dark:bg-neutral-800 text-neutral-600 dark:text-neutral-300
        rounded-full w-10 h-10 text-sm transition-colors duration-300 ${className}`}
      >
        {src ? (
          <img src={src} alt={alt} className="w-full h-full object-cover" />
        ) : initials ? (
          <span className="font-medium tracking-tight">
            {initials}
          </span>
        ) : (
          <User className="w-1/2 h-1/2 opacity-70" strokeWidth={2} />
        )}
      </div>
      <span
        className={`absolute top-0 right-0 block h-2.5 w-2.5 rounded-full ${indicatorColor} 
        ring-2 ring-white dark:ring-[#0a0a0a] transition-colors duration-300`}
      />
    </div>
  );
};

export default AvatarWithNotification;

Avatar with Active Badge

An avatar featuring a larger bottom-right active dot (e.g. online presence).

import React from "react";
import { User } from "lucide-react";

interface AvatarProps {
  size?: "sm" | "md" | "lg";
  src?: string;
  alt?: string;
  initials?: string;
  className?: string;
}

interface AvatarWithIndicatorProps extends AvatarProps {
  indicatorColor?: string;
}

const AvatarWithActiveBadge: React.FC<AvatarWithIndicatorProps> = ({
  src,
  alt = "User avatar",
  initials,
  indicatorColor = "bg-emerald-500",
  className = "",
}) => {
  return (
    <div className="relative inline-block">
      <div
        className={`relative inline-flex items-center justify-center overflow-hidden 
        bg-neutral-100 dark:bg-neutral-800 text-neutral-600 dark:text-neutral-300
        rounded-full w-10 h-10 text-sm transition-colors duration-300 ${className}`}
      >
        {src ? (
          <img src={src} alt={alt} className="w-full h-full object-cover" />
        ) : initials ? (
          <span className="font-medium tracking-tight">
            {initials}
          </span>
        ) : (
          <User className="w-1/2 h-1/2 opacity-70" strokeWidth={2} />
        )}
      </div>
      <span
        className={`absolute bottom-0 right-0 block h-3 w-3 rounded-full ${indicatorColor} 
        ring-2 ring-white dark:ring-[#0a0a0a] transition-colors duration-300`}
      />
    </div>
  );
};

export default AvatarWithActiveBadge;

Avatar Group

A refined stack of avatars using a subtle interactive hover elevation.

import React from "react";
import { User } from "lucide-react";

interface AvatarGroupProps {
  max?: number;
}

const AvatarGroup: React.FC<AvatarGroupProps> = ({ max = 3 }) => {
  const avatars = [
    { src: "/pfp.jpg", alt: "User 1" },
    { initials: "JD" },
    { src: "/pfp.jpg", alt: "User 2" },
    { initials: "AS" },
    { src: "/pfp.jpg", alt: "User 3" },
  ];

  const visibleAvatars = avatars.slice(0, max);
  const remainingCount = Math.max(avatars.length - max, 0);

  return (
    <div className="flex -space-x-2.5">
      {visibleAvatars.map((avatar, index) => (
        <div
          key={index}
          className="relative inline-flex items-center justify-center overflow-hidden 
          bg-neutral-100 dark:bg-neutral-800 text-neutral-600 dark:text-neutral-300
          rounded-full ring-[2px] ring-white dark:ring-[#0a0a0a]
          w-10 h-10 text-sm transition-transform hover:z-10 hover:-translate-y-1 duration-300"
        >
          {avatar.src ? (
            <img
              src={avatar.src}
              alt={avatar.alt || "User avatar"}
              className="w-full h-full object-cover"
            />
          ) : avatar.initials ? (
            <span className="font-medium tracking-tight">
              {avatar.initials}
            </span>
          ) : (
            <User className="w-1/2 h-1/2 opacity-70" strokeWidth={2} />
          )}
        </div>
      ))}
      {remainingCount > 0 && (
        <div
          className="relative inline-flex items-center justify-center 
          bg-neutral-50 dark:bg-neutral-900 
          text-neutral-500 dark:text-neutral-400 font-medium rounded-full 
          ring-[2px] ring-white dark:ring-[#0a0a0a] border border-neutral-200 dark:border-neutral-800
          w-10 h-10 text-[13px] tracking-tight transition-transform hover:z-10 hover:-translate-y-1 duration-300"
        >
          +{remainingCount}
        </div>
      )}
    </div>
  );
};

export default AvatarGroup;

Square Avatar

A modern, slightly rounded square variant perfect for logos or distinguishing organizations from standard users.

import React from "react";
import { User } from "lucide-react";

interface AvatarProps {
  size?: "sm" | "md" | "lg";
  src?: string;
  alt?: string;
  initials?: string;
  className?: string;
}

const SquareAvatar: React.FC<AvatarProps> = ({
  src,
  alt = "User avatar",
  initials,
  className = "",
}) => {
  return (
    <div
      className={`relative inline-flex items-center justify-center overflow-hidden 
      bg-neutral-100 dark:bg-neutral-800 text-neutral-600 dark:text-neutral-300
      rounded-xl w-12 h-12 text-sm transition-colors duration-300 ${className}`}
    >
      {src ? (
        <img src={src} alt={alt} className="w-full h-full object-cover" />
      ) : initials ? (
        <span className="font-medium tracking-tight text-base">
          {initials}
        </span>
      ) : (
        <User className="w-1/2 h-1/2 opacity-70" strokeWidth={2} />
      )}
    </div>
  );
};

export default SquareAvatar;

Status Ring Avatar

A premium avatar utilizing an elegant outer border to indicate status (e.g. streaming, highlighting), detached from the core image via a padding gap.

import React from "react";
import { User } from "lucide-react";

interface AvatarProps {
  size?: "sm" | "md" | "lg";
  src?: string;
  alt?: string;
  initials?: string;
  className?: string;
}

interface StatusRingAvatarProps extends AvatarProps {
  statusColor?: string;
  isOnline?: boolean;
}

const StatusRingAvatar: React.FC<StatusRingAvatarProps> = ({
  src,
  alt = "User avatar",
  initials,
  statusColor = "border-emerald-500",
  isOnline = true,
  className = "",
}) => {
  return (
    <div className={`relative inline-block ${isOnline ? statusColor : 'border-neutral-300 dark:border-neutral-700'} border-2 rounded-full p-[2px] transition-colors duration-300`}>
      <div
        className={`relative inline-flex items-center justify-center overflow-hidden 
        bg-neutral-100 dark:bg-neutral-800 text-neutral-600 dark:text-neutral-300
        rounded-full w-10 h-10 text-sm transition-colors duration-300 ${className}`}
      >
        {src ? (
          <img src={src} alt={alt} className="w-full h-full object-cover" />
        ) : initials ? (
          <span className="font-medium tracking-tight">
            {initials}
          </span>
        ) : (
          <User className="w-1/2 h-1/2 opacity-70" strokeWidth={2} />
        )}
      </div>
    </div>
  );
};

export default StatusRingAvatar;