# Avatar

An accessible React avatar for Next.js and Tailwind CSS: a picture or initials in three sizes, alone or in an overlapping group, built on Radix Avatar.

Source: https://ui.fewtone.com/components/avatar

## Installation

```bash
npx shadcn@latest add https://ui.fewtone.com/r/avatar.json
```

## Usage

```tsx
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"

export function UserAvatar({ user }) {
  return (
    <Avatar>
      <AvatarImage src={user.image} alt={user.name} />
      <AvatarFallback>{user.initials}</AvatarFallback>
    </Avatar>
  )
}
```

## API reference

### Avatar

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | 24, 32 or 40px. A group's count follows the avatars beside it. |

### AvatarImage

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `src` | `string` | – | The picture's URL. |
| `alt` | `string` | – | The person's name. The initials carry it while they stand in. Use alt="" when the name is written beside the avatar. |
| `onLoadingStatusChange` | `(status: "idle" \| "loading" \| "loaded" \| "error") => void` | – | Called as the picture loads, or fails to. |

### AvatarFallback

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `delayMs` | `number` | – | Wait this long before showing the initials, so a quick picture never flashes them. |

### AvatarGroup

| Prop | Type | Default | Description |
| --- | --- | --- | --- |

### AvatarGroupCount

| Prop | Type | Default | Description |
| --- | --- | --- | --- |

**When to use it:** Use Avatar for a person or account: a picture with initials as the fallback. Give the picture the person's name as alt, or alt="" when the name is written beside it. Use AvatarGroup with AvatarGroupCount to show a team or the people on a document.
**Built on:** Radix Avatar.
**npm packages (installed by the CLI):** class-variance-authority@^0.7.1, motion@^14.0.0, radix-ui@^1.7.0.

## Examples

### Sizes

Each size with a picture and with initials, and a group with a count. A picture comes in through the blur once it has loaded, over the initials, so nothing jumps.

```tsx
import {
  Avatar,
  AvatarFallback,
  AvatarGroup,
  AvatarGroupCount,
  AvatarImage,
} from "@/components/ui/avatar";

/*
 * Pictures drawn as small grey SVGs, so the demo works offline. Use your people's photo URLs instead: when one is
 * missing or can't load, the initials stay, named by the alt.
 */
const picture = (shapes: string) =>
  `data:image/svg+xml,${encodeURIComponent(
    `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><rect width="40" height="40" fill="white"/>${shapes}</svg>`,
  )}`;

const people = [
  {
    name: "Olivia Martin",
    initials: "OM",
    picture: picture(
      '<rect width="40" height="40" fill-opacity=".7"/><circle cx="26" cy="14" r="6" fill="white" fill-opacity=".75"/><path d="M0 30q11-8 21-3t19-2v15H0z" fill-opacity=".45"/>',
    ),
  },
  { name: "Jackson Lee", initials: "JL" },
  {
    name: "Isabella Nguyen",
    initials: "IN",
    picture: picture(
      '<rect width="40" height="40" fill-opacity=".35"/><path d="M0 34 13 16l8 10 6-7 13 15v6H0z" fill-opacity=".55"/><path d="M0 40v-4l13-9 9 6 6-4 12 7v4z" fill-opacity=".35"/>',
    ),
  },
  { name: "William Kim", initials: "WK" },
];

const sizes = [
  { size: "sm", label: "Small" },
  { size: "md", label: "Medium" },
  { size: "lg", label: "Large" },
] as const;

/* Each size with a picture and with initials, then a group with a count, each named underneath */
export default function AvatarSizes() {
  return (
    <ul className="flex flex-wrap items-end justify-center gap-x-10 gap-y-6">
      {sizes.map(({ size, label }) => (
        <li key={size} className="flex flex-col items-center gap-2">
          <div className="flex items-center gap-3">
            {people.slice(0, 2).map((person) => (
              <Avatar key={person.name} size={size}>
                <AvatarImage src={person.picture} alt={person.name} />
                <AvatarFallback>{person.initials}</AvatarFallback>
              </Avatar>
            ))}
          </div>
          <span className="text-xs text-muted-foreground">{label}</span>
        </li>
      ))}
      <li className="flex flex-col items-center gap-2">
        <AvatarGroup aria-label="Team, 7 people">
          {people.map((person) => (
            <Avatar key={person.name}>
              <AvatarImage src={person.picture} alt={person.name} />
              <AvatarFallback>{person.initials}</AvatarFallback>
            </Avatar>
          ))}
          <AvatarGroupCount>+3</AvatarGroupCount>
        </AvatarGroup>
        <span className="text-xs text-muted-foreground">Group</span>
      </li>
    </ul>
  );
}
```

### With a name

With the name written beside it, give the picture alt="": the avatar is hidden from screen readers and the name is read once.

```tsx
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";

type Member = { name: string; email: string; initials: string; picture?: string };

// No pictures yet, so the initials stand in
const members: Member[] = [
  { name: "Sofia Davis", email: "sofia@example.com", initials: "SD" },
  { name: "Jackson Lee", email: "jackson@example.com", initials: "JL" },
  { name: "William Kim", email: "will@example.com", initials: "WK" },
];

/*
 * With the name written beside it, the avatar is decoration: alt="" hides the picture and the initials from
 * screen readers, so the name is read once.
 */
export default function AvatarWithName() {
  return (
    <ul className="grid w-full max-w-xs gap-4">
      {members.map((member) => (
        <li key={member.email} className="flex items-center gap-3">
          <Avatar size="lg">
            <AvatarImage src={member.picture} alt="" />
            <AvatarFallback>{member.initials}</AvatarFallback>
          </Avatar>
          <div className="grid min-w-0">
            <span className="truncate text-sm font-medium">{member.name}</span>
            <span className="truncate text-sm text-muted-foreground">{member.email}</span>
          </div>
        </li>
      ))}
    </ul>
  );
}
```

## Related

- [Badge](https://ui.fewtone.com/components/badge.md): An accessible React badge for Next.js and Tailwind CSS: small status labels in five variants, including one with a light travelling round its edge.
- [Card](https://ui.fewtone.com/components/card.md): A React card for Next.js and Tailwind CSS: a surface for grouped content with header, action, content and footer parts, a small size and a link style.
