# Avatar (/ui/components/react/avatar)



<Playground component="avatar" />

## Usage [#usage]

```tsx
import { Avatar, AvatarImage, AvatarFallback } from '@appica/ui-react/avatar'
```

```tsx
<Avatar>
  <AvatarImage src="/avatars/01.jpg" alt="Sarah Jenkins" />
  <AvatarFallback>SJ</AvatarFallback>
</Avatar>
```

`Avatar` represents a person or entity. Compose it from its parts, all under `@appica/ui-react/avatar`:

* **`Avatar`** — the root that sets `size` and `shape` and clips its children to the rounded silhouette.
* **`AvatarImage`** — the photo. Base UI preloads the `src` and only swaps it in once it has loaded, so a broken or slow image never flashes.
* **`AvatarFallback`** — what shows until (or unless) the image loads: initials or an icon.
* **`AvatarBadge`** — an optional status dot in the corner.
* **`AvatarGroup`** — a wrapper that overlaps a row of avatars and forwards a shared `size`/`shape`.

The whole component is sized in `em`, so a single `size` (a preset or a pixel number) scales the image, fallback text, and status badge together.

## Examples [#examples]

### Default [#default]

An `AvatarImage` with an `AvatarFallback` beneath it. The image is shown once loaded; until then — or if it fails — the fallback initials take its place.

```tsx
import { Avatar, AvatarImage, AvatarFallback } from '@appica/ui-react/avatar'

export default function AvatarDefault() {
  return (
    <Avatar size="lg">
      <AvatarImage src="/avatars/01.jpg" alt="Sarah Jenkins" />
      <AvatarFallback>SJ</AvatarFallback>
    </Avatar>
  )
}
```

### Fallback [#fallback]

When the image is missing, still loading, or fails to load, the `AvatarFallback` renders instead. Use initials for people, or an icon for a generic placeholder.

```tsx
import { Avatar, AvatarImage, AvatarFallback } from '@appica/ui-react/avatar'
import { UserFilled } from '@appica/icons-react'

export default function AvatarFallbackExample() {
  return (
    <div className="flex items-center gap-4">
      <Avatar size="lg">
        <AvatarImage src="/avatars/does-not-exist.jpg" alt="Sarah Jenkins" />
        <AvatarFallback>SJ</AvatarFallback>
      </Avatar>
      <Avatar size="lg">
        <AvatarFallback>MR</AvatarFallback>
      </Avatar>
      <Avatar size="lg">
        <AvatarFallback>
          <UserFilled />
        </AvatarFallback>
      </Avatar>
    </div>
  )
}
```

### Sizes [#sizes]

Seven presets run from `2xs` to `2xl`. Because the avatar is sized in `em`, the fallback text and status badge scale along with the image.

```tsx
import { Avatar, AvatarImage, AvatarFallback } from '@appica/ui-react/avatar'

const sizes = ['2xs', 'xs', 'sm', 'md', 'lg', 'xl'] as const

export default function AvatarSizes() {
  return (
    <div className="flex flex-wrap items-center justify-center gap-4">
      {sizes.map((size) => (
        <Avatar key={size} size={size}>
          <AvatarImage src="/avatars/02.jpg" alt="Daniel Reyes" />
          <AvatarFallback>DR</AvatarFallback>
        </Avatar>
      ))}
    </div>
  )
}
```

### Custom size [#custom-size]

Pass a number to `size` for an exact pixel dimension when a preset doesn't fit — say to match a specific line height. It drives the root's `font-size`, so everything inside still scales proportionally.

```tsx
import { Avatar, AvatarImage, AvatarFallback } from '@appica/ui-react/avatar'

export default function AvatarCustomSize() {
  return (
    <div className="flex items-center gap-4">
      <Avatar size={28}>
        <AvatarImage src="/avatars/04.jpg" alt="Ava Thompson" />
        <AvatarFallback>AT</AvatarFallback>
      </Avatar>
      <Avatar size={44}>
        <AvatarImage src="/avatars/04.jpg" alt="Ava Thompson" />
        <AvatarFallback>AT</AvatarFallback>
      </Avatar>
      <Avatar size={72}>
        <AvatarImage src="/avatars/04.jpg" alt="Ava Thompson" />
        <AvatarFallback>AT</AvatarFallback>
      </Avatar>
    </div>
  )
}
```

### Shape [#shape]

`shape="circle"` (the default) renders a full circle; `shape="rounded"` uses a squircle-style rounded square for a more app-like look.

```tsx
import { Avatar, AvatarImage, AvatarFallback } from '@appica/ui-react/avatar'

export default function AvatarShape() {
  return (
    <div className="flex items-center gap-4">
      <Avatar size="lg" shape="circle">
        <AvatarImage src="/avatars/03.jpg" alt="Mateo Rossi" />
        <AvatarFallback>MR</AvatarFallback>
      </Avatar>
      <Avatar size="lg" shape="rounded">
        <AvatarImage src="/avatars/03.jpg" alt="Mateo Rossi" />
        <AvatarFallback>MR</AvatarFallback>
      </Avatar>
    </div>
  )
}
```

### Status badge [#status-badge]

Drop an `AvatarBadge` inside the avatar for a corner status dot. Add `animate` for a gentle pulsing ping that draws the eye to an online indicator, and recolor it with a `text-*` class.

```tsx
import { Avatar, AvatarImage, AvatarFallback, AvatarBadge } from '@appica/ui-react/avatar'

export default function AvatarStatus() {
  return (
    <div className="flex items-center gap-4">
      <Avatar size="lg">
        <AvatarImage src="/avatars/08.jpg" alt="Liam Hudson" />
        <AvatarFallback>LH</AvatarFallback>
        <AvatarBadge />
      </Avatar>
      <Avatar size="lg">
        <AvatarImage src="/avatars/09.jpg" alt="Emma Garcia" />
        <AvatarFallback>EG</AvatarFallback>
        <AvatarBadge animate />
      </Avatar>
      <Avatar size="lg">
        <AvatarImage src="/avatars/06.jpg" alt="Lucas Müller" />
        <AvatarFallback>LM</AvatarFallback>
        <AvatarBadge className="text-foreground-subtle" />
      </Avatar>
    </div>
  )
}
```

### Avatar group [#avatar-group]

`AvatarGroup` overlaps a row of avatars and rings each one with the background color so they read as a stack. It forwards a shared `size`/`shape` to its children, and any non-image avatar — like a `+5` counter — sits in the same rhythm.

```tsx
import { Avatar, AvatarImage, AvatarFallback, AvatarGroup } from '@appica/ui-react/avatar'

const people = [
  { src: '/avatars/01.jpg', alt: 'Sarah Jenkins', initials: 'SJ' },
  { src: '/avatars/02.jpg', alt: 'Liam Hudson', initials: 'LH' },
  { src: '/avatars/03.jpg', alt: 'Mateo Rossi', initials: 'MR' },
  { src: '/avatars/04.jpg', alt: 'Ava Thompson', initials: 'AT' },
]

export default function AvatarGroupExample() {
  return (
    <AvatarGroup size="md">
      {people.map((person) => (
        <Avatar key={person.src}>
          <AvatarImage src={person.src} alt={person.alt} />
          <AvatarFallback>{person.initials}</AvatarFallback>
        </Avatar>
      ))}
      <Avatar>
        <AvatarFallback className="text-foreground-muted text-sm">+5</AvatarFallback>
      </Avatar>
    </AvatarGroup>
  )
}
```

### Next.js Image [#nextjs-image]

To serve optimized images, pass a Next.js `<Image>` to `AvatarImage`'s `render` prop. The wrapper lifts the `src` so Base UI's preloader still drives the fallback, and applies its own `object-cover` and rounded-corner classes to the rendered `<Image>`. Give the `Image` a `width`/`height` that matches the avatar's pixel size.

```tsx
import Image from 'next/image'
import { Avatar, AvatarImage, AvatarFallback } from '@appica/ui-react/avatar'

export default function AvatarNextImage() {
  return (
    <Avatar size="xl">
      <AvatarImage render={<Image src="/avatars/08.jpg" alt="Liam Hudson" width={64} height={64} />} />
      <AvatarFallback>LH</AvatarFallback>
    </Avatar>
  )
}
```

### Loading animation [#loading-animation]

`AvatarFallback` renders until the image finishes loading, so dropping a [`Skeleton`](/ui/components/react/skeleton) inside it gives a shimmering placeholder that Base UI swaps for the photo automatically — no extra state needed. Press **Reload** to fetch a fresh copy and watch it again.

```tsx
'use client'

import { useState, useEffect } from 'react'
import { Avatar, AvatarImage, AvatarFallback } from '@appica/ui-react/avatar'
import { Skeleton } from '@appica/ui-react/skeleton'
import { Button } from '@appica/ui-react/button'

export default function AvatarLoading() {
  const [src, setSrc] = useState<string>()
  const [nonce, setNonce] = useState(0)

  useEffect(() => {
    setSrc(undefined)
    // Demo only: defer the image ~2.5s so the loading skeleton stays visible.
    const id = setTimeout(() => setSrc(`/avatars/09.jpg?reload=${nonce}`), 2500)
    return () => clearTimeout(id)
  }, [nonce])

  return (
    <div className="flex flex-col items-center gap-4">
      <Avatar size="xl" className="bg-transparent">
        <AvatarImage src={src} alt="Emma Garcia" />
        <AvatarFallback>
          <Skeleton className="size-full rounded-[inherit]" />
        </AvatarFallback>
      </Avatar>
      <Button variant="outline" size="sm" onClick={() => setNonce((n) => n + 1)} disabled={!src}>
        Reload
      </Button>
    </div>
  )
}
```

## RTL [#rtl]

Every Appica UI component supports right-to-left layouts out of the box. Set the `dir` attribute on a container (commonly your `<html>` element) so CSS logical properties resolve correctly, and wrap your tree in `DirectionProvider` so direction-aware behavior follows the same direction.

```tsx
import { DirectionProvider } from '@appica/ui-react/providers/direction-provider'

export default function RootLayout({ children }) {
  return (
    <html lang="ar" dir="rtl">
      <body>
        <DirectionProvider dir="rtl">{children}</DirectionProvider>
      </body>
    </html>
  )
}
```

The status badge moves to the start (right) corner and the group stacks from the right, because both are expressed with logical properties. For setup details and caveats, see the [RTL guide](/ui/docs/react/rtl).

<RtlPreview component="avatar" />

## API reference [#api-reference]

`Avatar` wraps [Base UI's Avatar](https://base-ui.com/react/components/avatar). Each part forwards `ref` and its remaining attributes to the matching Base UI primitive — `AvatarImage` preloads `src` and only mounts the image once it resolves. `AvatarBadge` and `AvatarGroup` are Appica additions. See the Base UI docs for the complete API.

### Avatar [#avatar]

The root. Renders a `<span>` that sizes and clips its children.

| Prop        | <ColMinWidth width="200">Type</ColMinWidth>                                   | Default    | <ColMinWidth width="220">Description</ColMinWidth>              |
| ----------- | ----------------------------------------------------------------------------- | ---------- | --------------------------------------------------------------- |
| `size`      | <Code>'2xs' \| 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| '2xl' \| number</Code> | `'md'`     | A preset scale, or a pixel number for an exact size.            |
| `shape`     | <Code>'circle' \| 'rounded'</Code>                                            | `'circle'` | Full circle or rounded square.                                  |
| `render`    | <Code>ReactElement \| ((props, state) => ReactElement)</Code>                 | —          | Replace the root element, or compose it with another component. |
| `className` | `string`                                                                      | —          | Extra classes, merged via `tailwind-merge`.                     |

### AvatarImage [#avatarimage]

The photo. Renders an `<img>` (or the `render` element) once the source has loaded.

| Prop                    | <ColMinWidth width="200">Type</ColMinWidth>                               | Default | <ColMinWidth width="220">Description</ColMinWidth>               |
| ----------------------- | ------------------------------------------------------------------------- | ------- | ---------------------------------------------------------------- |
| `src`                   | `string`                                                                  | —       | Image URL. Lifted from the `render` element when omitted.        |
| `alt`                   | `string`                                                                  | —       | Alternative text describing the person/entity.                   |
| `onLoadingStatusChange` | <Code>(status: 'idle' \| 'loading' \| 'loaded' \| 'error') => void</Code> | —       | Fires as the image moves through its loading lifecycle.          |
| `render`                | <Code>ReactElement \| ((props, state) => ReactElement)</Code>             | —       | Swap the `<img>` for another element — e.g. a Next.js `<Image>`. |
| `className`             | `string`                                                                  | —       | Extra classes, merged via `tailwind-merge`.                      |

### AvatarFallback [#avatarfallback]

Shown until — or unless — the image loads. Renders a `<span>`.

| Prop        | <ColMinWidth width="200">Type</ColMinWidth>                   | Default | <ColMinWidth width="220">Description</ColMinWidth>                               |
| ----------- | ------------------------------------------------------------- | ------- | -------------------------------------------------------------------------------- |
| `delay`     | `number`                                                      | —       | Milliseconds to wait before showing the fallback (avoids a flash on fast loads). |
| `children`  | `ReactNode`                                                   | —       | Initials or an icon. Text is auto-shrunk; an `svg` is shown at full size.        |
| `render`    | <Code>ReactElement \| ((props, state) => ReactElement)</Code> | —       | Replace the fallback element.                                                    |
| `className` | `string`                                                      | —       | Extra classes, merged via `tailwind-merge`.                                      |

### AvatarBadge [#avatarbadge]

An optional status dot in the corner. Renders a `<span>`.

| Prop        | Type      | Default | Description                                                       |
| ----------- | --------- | ------- | ----------------------------------------------------------------- |
| `animate`   | `boolean` | `false` | Add a pulsing ping behind the dot (skipped under reduced motion). |
| `className` | `string`  | —       | Extra classes — recolor with a `text-*` class.                    |

### AvatarGroup [#avatargroup]

Overlaps a row of avatars and forwards a shared size/shape. Renders a `<div>`.

| Prop          | <ColMinWidth width="200">Type</ColMinWidth> | Default        | <ColMinWidth width="220">Description</ColMinWidth>               |
| ------------- | ------------------------------------------- | -------------- | ---------------------------------------------------------------- |
| `size`        | `Avatar['size']`                            | —              | Default size applied to child avatars that don't set their own.  |
| `shape`       | `Avatar['shape']`                           | —              | Default shape applied to child avatars that don't set their own. |
| `orientation` | <Code>'horizontal' \| 'vertical'</Code>     | `'horizontal'` | Stack the avatars in a row or a column.                          |
| `className`   | `string`                                    | —              | Extra classes, merged via `tailwind-merge`.                      |

A child `Avatar`'s own `size`/`shape` always wins over the group default.

## Accessibility [#accessibility]

* Give every meaningful `AvatarImage` an `alt` that names the person or entity. For a purely decorative avatar, use `alt=""`.
* The `AvatarFallback` text (initials) is visible content, so it's announced; for an icon-only fallback, the icon is decorative — make sure the surrounding context names the user.
* `AvatarBadge` is a visual status indicator. If the status is important, convey it in text nearby (e.g. "Online") rather than relying on the dot's color alone.
* In an `AvatarGroup`, each avatar keeps its own accessible name; consider an `aria-label` on the group (e.g. "Project members") and visible text for any `+N` overflow count.
* The status badge's pulsing animation is skipped when the user prefers reduced motion.
