Avatar

Component

Free, copy-pasteable Tailwind CSS Avatar component. Accessible, fully responsive, dark-mode ready, and customizable.

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;