27.5k

Avatar

Migration guide for Avatar from HeroUI v2 to v3

Refer to the v3 Avatar documentation for complete API reference, styling guide, and advanced examples. This guide only focuses on migrating from HeroUI v2.

Overview

The Avatar component in HeroUI v3 has been redesigned with a compound component pattern, requiring explicit structure with Avatar.Image and Avatar.Fallback components.

Structure Changes

v2: Single Component with Props

In v2, Avatar was a single component that accepted props for image source, name, fallback, and other elements:

import { Avatar } from "@heroui/react";

<Avatar 
  src="https://example.com/avatar.jpg"
  name="John Doe"
  showFallback
/>

v3: Compound Component Structure

In v3, Avatar uses a compound component pattern with explicit subcomponents:

import { Avatar } from "@heroui/react";

<Avatar>
  <Avatar.Image src="https://example.com/avatar.jpg" alt="John Doe" />
  <Avatar.Fallback>JD</Avatar.Fallback>
</Avatar>

Key Changes

1. Component Structure

v2: Single Avatar component with props
v3: Compound components: Avatar, Avatar.Image, Avatar.Fallback

2. Image and Fallback Handling

v2: Used src, name, showFallback, and fallback props
v3: Must explicitly render <Avatar.Image /> and <Avatar.Fallback /> components

3. Color Props

v2 Colorv3 ColorNotes
defaultdefaultSame
primaryaccentRenamed
secondarydefaultUse default color
successsuccessSame
warningwarningSame
dangerdangerSame

4. Removed Props

The following props are no longer available in v3:

  • name - Generate initials manually and pass to <Avatar.Fallback />
  • showFallback - Fallback is always shown if image fails to load
  • icon - Place icon content directly in <Avatar.Fallback />
  • isBordered - Use Tailwind CSS classes like ring-2 ring-background
  • radius - Use Tailwind CSS classes like rounded-full, rounded-lg, etc.
  • isDisabled - Use Tailwind CSS classes with opacity
  • isFocusable - Not applicable (use asChild if needed)
  • getInitials - Generate initials manually
  • ImgComponent / imgProps - Use asChild prop on Avatar.Image if needed
  • onError - Use onError prop on Avatar.Image instead
  • classNames - Use className props on individual components

5. AvatarGroup Removed

v2: Had a dedicated AvatarGroup component
v3: No AvatarGroup component - create groups manually with CSS classes

Migration Examples

Basic Usage

import { Avatar } from "@heroui/react";

export default function App() {
  return (
    <Avatar 
      src="https://example.com/avatar.jpg"
      name="John Doe"
      showFallback
    />
  );
}
import { Avatar } from "@heroui/react";

export default function App() {
  return (
    <Avatar>
      <Avatar.Image 
        src="https://example.com/avatar.jpg" 
        alt="John Doe"
      />
      <Avatar.Fallback>JD</Avatar.Fallback>
    </Avatar>
  );
}

Sizes

<Avatar size="sm" src="..." />
<Avatar size="md" src="..." />
<Avatar size="lg" src="..." />
<Avatar size="sm">
  <Avatar.Image src="..." alt="..." />
  <Avatar.Fallback>S</Avatar.Fallback>
</Avatar>
<Avatar size="md">
  <Avatar.Image src="..." alt="..." />
  <Avatar.Fallback>M</Avatar.Fallback>
</Avatar>
<Avatar size="lg">
  <Avatar.Image src="..." alt="..." />
  <Avatar.Fallback>L</Avatar.Fallback>
</Avatar>

Colors

<Avatar color="primary" name="John" />
<Avatar color="success" name="Jane" />
<Avatar color="danger" name="Joe" />
<Avatar color="accent">
  <Avatar.Fallback>J</Avatar.Fallback>
</Avatar>
<Avatar color="success">
  <Avatar.Fallback>J</Avatar.Fallback>
</Avatar>
<Avatar color="danger">
  <Avatar.Fallback>J</Avatar.Fallback>
</Avatar>

Custom Fallback

import { Icon } from "@iconify/react";

<Avatar 
  src="https://broken-url.com/image.jpg"
  showFallback
  fallback={<Icon icon="mdi:account" />}
/>
import { Icon } from "@iconify/react";

<Avatar>
  <Avatar.Image 
    src="https://broken-url.com/image.jpg" 
    alt="User"
  />
  <Avatar.Fallback>
    <Icon icon="mdi:account" />
  </Avatar.Fallback>
</Avatar>

Bordered Avatar

<Avatar 
  isBordered
  src="https://example.com/avatar.jpg"
/>
<Avatar className="ring-2 ring-background">
  <Avatar.Image src="https://example.com/avatar.jpg" alt="User" />
  <Avatar.Fallback>U</Avatar.Fallback>
</Avatar>

Radius

<Avatar radius="full" src="..." />
<Avatar radius="lg" src="..." />
<Avatar radius="md" src="..." />
<Avatar className="rounded-full">
  <Avatar.Image src="..." alt="..." className="rounded-full" />
  <Avatar.Fallback className="rounded-full">F</Avatar.Fallback>
</Avatar>
<Avatar className="rounded-lg">
  <Avatar.Image src="..." alt="..." className="rounded-lg" />
  <Avatar.Fallback className="rounded-lg">L</Avatar.Fallback>
</Avatar>
<Avatar className="rounded-md">
  <Avatar.Image src="..." alt="..." className="rounded-md" />
  <Avatar.Fallback className="rounded-md">M</Avatar.Fallback>
</Avatar>

Avatar Group

import { Avatar, AvatarGroup } from "@heroui/react";

<AvatarGroup isBordered>
  <Avatar src="https://example.com/1.jpg" />
  <Avatar src="https://example.com/2.jpg" />
  <Avatar src="https://example.com/3.jpg" />
</AvatarGroup>
import { Avatar } from "@heroui/react";

<div className="flex -space-x-2">
  <Avatar className="ring-2 ring-background">
    <Avatar.Image src="https://example.com/1.jpg" alt="User 1" />
    <Avatar.Fallback>U1</Avatar.Fallback>
  </Avatar>
  <Avatar className="ring-2 ring-background">
    <Avatar.Image src="https://example.com/2.jpg" alt="User 2" />
    <Avatar.Fallback>U2</Avatar.Fallback>
  </Avatar>
  <Avatar className="ring-2 ring-background">
    <Avatar.Image src="https://example.com/3.jpg" alt="User 3" />
    <Avatar.Fallback>U3</Avatar.Fallback>
  </Avatar>
</div>

Avatar Group with Max Count

import { Avatar, AvatarGroup } from "@heroui/react";

<AvatarGroup max={3}>
  <Avatar src="https://example.com/1.jpg" />
  <Avatar src="https://example.com/2.jpg" />
  <Avatar src="https://example.com/3.jpg" />
  <Avatar src="https://example.com/4.jpg" />
  <Avatar src="https://example.com/5.jpg" />
</AvatarGroup>
import { Avatar } from "@heroui/react";

const users = [
  { id: 1, src: "https://example.com/1.jpg", name: "User 1" },
  { id: 2, src: "https://example.com/2.jpg", name: "User 2" },
  { id: 3, src: "https://example.com/3.jpg", name: "User 3" },
  { id: 4, src: "https://example.com/4.jpg", name: "User 4" },
  { id: 5, src: "https://example.com/5.jpg", name: "User 5" },
];

<div className="flex -space-x-2">
  {users.slice(0, 3).map((user) => (
    <Avatar key={user.id} className="ring-2 ring-background">
      <Avatar.Image src={user.src} alt={user.name} />
      <Avatar.Fallback>
        {user.name.split(" ").map(n => n[0]).join("")}
      </Avatar.Fallback>
    </Avatar>
  ))}
  <Avatar className="ring-2 ring-background">
    <Avatar.Fallback className="border-none">
      +{users.length - 3}
    </Avatar.Fallback>
  </Avatar>
</div>

Disabled Avatar

<Avatar 
  isDisabled
  src="https://example.com/avatar.jpg"
/>
<Avatar className="opacity-50 cursor-not-allowed">
  <Avatar.Image src="https://example.com/avatar.jpg" alt="User" />
  <Avatar.Fallback>U</Avatar.Fallback>
</Avatar>

Variants

{/* v2 doesn't have variants, but uses color prop */}
<Avatar color="primary" name="John" />
{/* v3 has variant prop */}
<Avatar variant="soft" color="accent">
  <Avatar.Fallback>J</Avatar.Fallback>
</Avatar>

Styling Changes

v2: classNames Prop

<Avatar 
  classNames={{
    base: "custom-base",
    img: "custom-img",
    fallback: "custom-fallback"
  }}
/>

v3: Direct className Props

<Avatar className="custom-base">
  <Avatar.Image className="custom-img" src="..." alt="..." />
  <Avatar.Fallback className="custom-fallback">
    JD
  </Avatar.Fallback>
</Avatar>

Component Anatomy

The v3 Avatar follows this structure:

Avatar (Root)
  ├── Avatar.Image (optional)
  └── Avatar.Fallback (always shown if image fails or not provided)

Helper Function for Initials

Since v3 doesn't have a name prop, you'll need to generate initials manually:

function getInitials(name: string): string {
  return name
    .split(" ")
    .map(n => n[0])
    .join("")
    .toUpperCase()
    .slice(0, 2);
}

// Usage
<Avatar>
  <Avatar.Fallback>{getInitials("John Doe")}</Avatar.Fallback>
</Avatar>

Breaking Changes Summary

  1. Component Structure: Must use compound components (Avatar.Image, Avatar.Fallback)
  2. Name Prop Removed: Generate initials manually
  3. ShowFallback Removed: Fallback always shows if image fails
  4. Color Mapping: primaryaccent, secondarydefault
  5. Bordered Removed: Use Tailwind ring-2 ring-background classes
  6. Radius Removed: Use Tailwind rounded-* classes
  7. Disabled Removed: Use Tailwind opacity-50 classes
  8. AvatarGroup Removed: Create groups manually with CSS
  9. Icon Prop Removed: Place icon content in Avatar.Fallback
  10. ClassNames Removed: Use className props on individual components

Tips for Migration

  1. Start with structure: Convert to compound components first
  2. Generate initials: Create a helper function for name-to-initials conversion
  3. Handle fallbacks: Always include <Avatar.Fallback /> for better UX
  4. Use Tailwind: Many removed props can be replaced with Tailwind utility classes
  5. Avatar groups: Use -space-x-2 and ring-2 ring-background for overlapping avatars
  6. Image alt text: Always provide alt prop on Avatar.Image for accessibility

Need Help?

For v3 Avatar features and API:

For community support: