# Avatar

A round picture for a person, a team or an organization, with a fallback.

```tsx
import { Avatar, AvatarBadge, AvatarFallback } from 'ferry-ui'

export default function AvatarHero() {
  return (
    <div className="flex items-center gap-3">
      <Avatar>
        <AvatarFallback>MC</AvatarFallback>
        <AvatarBadge className="bg-success" role="img" aria-label="Online" />
      </Avatar>
      <div className="flex flex-col">
        <span className="text-sm font-medium text-foreground">Maya Chen</span>
        <span className="text-[13px] text-foreground-light">maya@example.com</span>
      </div>
    </div>
  )
}
```

## Usage guidelines

- **People, teams and organizations.** Use an avatar for a person, a team or an organization.
- **The kind of an entity is not an avatar.** For an icon that shows the kind of an entity, use [Icon Box](/docs/components/icon-box).
- **Always add a fallback.** `AvatarImage` shows only after the picture loads. `AvatarFallback` fills the frame until then.
- **Limit a group.** Show a few avatars in `AvatarGroup`. Put the number of the others in `AvatarGroupCount`.

## Anatomy

Import the parts and put them together.

```tsx title="Anatomy"

<AvatarGroup>
  <Avatar>
    <AvatarImage />
    <AvatarFallback />
    <AvatarBadge />
  </Avatar>
  <AvatarGroupCount />
</AvatarGroup>
```

| Part | Role |
| --- | --- |
| `Avatar` | The round frame. It sets the size. |
| `AvatarImage` | The picture. It shows after the picture loads. |
| `AvatarFallback` | Initials or an icon. It shows when there is no picture. |
| `AvatarBadge` | A small dot at the bottom right of the avatar. |
| `AvatarGroup` | A row of avatars that overlap. |
| `AvatarGroupCount` | The last item of a group, for example "+5". |

## Examples

### Picture and fallback

Give the URL of the picture to `AvatarImage`. Put the initials of the person in `AvatarFallback`.

```tsx
<Avatar>
  <AvatarImage src={member.photo} alt={member.name} />
  <AvatarFallback>MC</AvatarFallback>
</Avatar>
```

If the picture fails, the fallback stays in view. The fallback can be initials or an icon. In this demo, the first picture cannot load.

```tsx
import { Avatar, AvatarFallback, AvatarImage } from 'ferry-ui'
import { User } from 'lucide-react'

export default function AvatarFallbackDemo() {
  return (
    <>
      <Avatar>
        {/* This picture cannot load: the initials stay in view. */}
        <AvatarImage src="data:image/png;base64,AA==" alt="Sam Patel" />
        <AvatarFallback>SP</AvatarFallback>
      </Avatar>
      <Avatar>
        <AvatarFallback>AL</AvatarFallback>
      </Avatar>
      <Avatar>
        <AvatarFallback>
          <User className="size-4" />
        </AvatarFallback>
      </Avatar>
    </>
  )
}
```

To prevent a flash of the fallback on a fast network, set `delayMs` on `AvatarFallback`.

### Sizes

The `size` prop sets the diameter. The fallback text and the badge follow the size.

```tsx
import { Avatar, AvatarFallback } from 'ferry-ui'

const SIZES = ['sm', 'md', 'lg'] as const

export default function AvatarSizes() {
  return (
    <>
      {SIZES.map((size) => (
        <Avatar key={size} size={size}>
          <AvatarFallback>JR</AvatarFallback>
        </Avatar>
      ))}
    </>
  )
}
```

| Size | Diameter |
| --- | --- |
| `sm` | 24px |
| `md` | 32px (default) |
| `lg` | 40px |

### Organization

An avatar is round by default. For an organization, pass `className="rounded-md"`. The picture and the fallback get the same radius.

```tsx
import { Avatar, AvatarFallback } from 'ferry-ui'
import { Building2 } from 'lucide-react'

export default function AvatarOrganization() {
  return (
    <div className="flex items-center gap-3">
      <Avatar className="rounded-md">
        <AvatarFallback className="bg-primary-soft text-primary">
          <Building2 className="size-4" />
        </AvatarFallback>
      </Avatar>
      <div className="flex flex-col">
        <span className="text-sm font-medium text-foreground">Acme</span>
        <span className="text-[13px] text-foreground-light">12 members</span>
      </div>
    </div>
  )
}
```

### Badge

`AvatarBadge` adds a dot at the bottom right of the avatar. It has the primary color by default. Set another color with a token class, such as `bg-success`.

The badge can hold an icon. The icon does not show at the `sm` size.

```tsx
import { Avatar, AvatarBadge, AvatarFallback } from 'ferry-ui'
import { Check } from 'lucide-react'

export default function AvatarWithBadge() {
  return (
    <>
      <Avatar size="lg">
        <AvatarFallback>PN</AvatarFallback>
        <AvatarBadge className="bg-success" role="img" aria-label="Online" />
      </Avatar>
      <Avatar size="lg">
        <AvatarFallback>AW</AvatarFallback>
        <AvatarBadge className="bg-warning" role="img" aria-label="Away" />
      </Avatar>
      <Avatar size="lg">
        <AvatarFallback>OB</AvatarFallback>
        <AvatarBadge className="bg-foreground-muted" role="img" aria-label="Offline" />
      </Avatar>
      <Avatar size="lg">
        <AvatarFallback>DK</AvatarFallback>
        <AvatarBadge role="img" aria-label="Verified">
          <Check />
        </AvatarBadge>
      </Avatar>
    </>
  )
}
```

### Group

`AvatarGroup` puts the avatars in a row where they overlap. Add `AvatarGroupCount` as the last child for the members that are not in view.

```tsx
import { Avatar, AvatarFallback, AvatarGroup, AvatarGroupCount } from 'ferry-ui'

const MEMBERS = [
  { name: 'Maya Chen', initials: 'MC' },
  { name: 'Jordan Reyes', initials: 'JR' },
  { name: 'Priya Nair', initials: 'PN' },
  { name: 'Lucas Martin', initials: 'LM' },
]

export default function AvatarGroupDemo() {
  return (
    <AvatarGroup>
      {MEMBERS.map((member) => (
        <Avatar key={member.name}>
          <AvatarFallback>{member.initials}</AvatarFallback>
        </Avatar>
      ))}
      <AvatarGroupCount>+5</AvatarGroupCount>
    </AvatarGroup>
  )
}
```

### Count with an icon

`AvatarGroupCount` accepts text or an icon. With an icon, add hidden text for screen readers.

```tsx
import { Avatar, AvatarFallback, AvatarGroup, AvatarGroupCount } from 'ferry-ui'
import { Plus } from 'lucide-react'

const MEMBERS = [
  { name: 'Maya Chen', initials: 'MC' },
  { name: 'Jordan Reyes', initials: 'JR' },
  { name: 'Priya Nair', initials: 'PN' },
]

export default function AvatarGroupIcon() {
  return (
    <AvatarGroup>
      {MEMBERS.map((member) => (
        <Avatar key={member.name} size="sm">
          <AvatarFallback>{member.initials}</AvatarFallback>
        </Avatar>
      ))}
      <AvatarGroupCount>
        <Plus aria-hidden="true" />
        <span className="sr-only">12 more members</span>
      </AvatarGroupCount>
    </AvatarGroup>
  )
}
```

## Accessibility

- Give `AvatarImage` an `alt` text, usually the name of the person.
- `AvatarBadge` is a plain `<span>`. If the state matters, add `role="img"` and an `aria-label`.
- `AvatarGroupCount` is not interactive. To open the full list of members, put the group in a button or a link.

## API reference

`Avatar`, `AvatarImage` and `AvatarFallback` also accept the props of their Radix UI primitive. The other parts accept the attributes of their element.

### Avatar

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `size` | `"default" \| "sm" \| "md" \| "lg"` | `md` | Diameter: `sm` 24px, `md` 32px (default), `lg` 40px. Children (fallback text, badge) scale with it. `default` is a deprecated alias of `md`. |
| `asChild` | `boolean` |  |  |

### AvatarImage

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `onLoadingStatusChange` | `((status: ImageLoadingStatus) => void)` |  |  |
| `asChild` | `boolean` |  |  |

### AvatarFallback

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `delayMs` | `number` |  |  |
| `asChild` | `boolean` |  |  |

### AvatarBadge

`AvatarBadge` has no props of its own. It accepts the attributes of the element it renders.

### AvatarGroup

`AvatarGroup` has no props of its own. It accepts the attributes of the element it renders.

### AvatarGroupCount

`AvatarGroupCount` has no props of its own. It accepts the attributes of the element it renders.
