# Avatar (/docs/avatar)





`Avatar` wraps Ark UI's `Avatar` machine, which already tracks image-load state (`loading → loaded/error`): pass `src` and it renders the image once it loads, and falls back automatically — to `children`, to initials derived from `name`, or to a generic person icon — when there's no image or it fails to load. `color="name"` / `color="initials"` can derive a stable accent per person automatically, with no color picked by hand.

```tsx
import { Avatar } from '@42-central/ui-react/avatar';

<Avatar src={user.avatarUrl} name={user.fullName} color="pink" />
<Avatar name="Ada Lovelace" color="teal" />
<Avatar />
```

## Playground [#playground]

<story.Playground />

### Full prop browser [#full-prop-browser]

<story.WithControl />

## Fallback content [#fallback-content]

Explicit `children` always wins, then `name`-derived content, then a placeholder icon. This resolves the same way regardless of whether `src` is missing entirely or present but failed to load. `display` (`"initials"` by default, or `"name"`) controls which `name`-derived form is shown — `"name"` is a single leading letter, since the full name would overflow a small circle.

<Preview align="block" code="&#x22;<Avatar src=\&#x22;https://i.pravatar.cc/150?img=12\&#x22; name=\&#x22;Ada Lovelace\&#x22; color=\&#x22;pink\&#x22; />\n<Avatar name=\&#x22;Ada Lovelace\&#x22; color=\&#x22;pink\&#x22; />\n<Avatar name=\&#x22;Ada Lovelace\&#x22; display=\&#x22;name\&#x22; color=\&#x22;pink\&#x22; />\n<Avatar color=\&#x22;pink\&#x22;>AL</Avatar>\n<Avatar />&#x22;">
  <div className="flex flex-wrap items-center gap-3">
    <Avatar src="https://i.pravatar.cc/150?img=12" name="Ada Lovelace" color="pink" />

    <Avatar name="Ada Lovelace" color="pink" />

    <Avatar name="Ada Lovelace" display="name" color="pink" />

    <Avatar color="pink">
      AL
    </Avatar>

    <Avatar />
  </div>
</Preview>

## Colors [#colors]

No variant axis — `Avatar` is always the same soft-surface look (the same treatment `Pill` and `Badge`'s `light` variant use), neutral gray by default. Pass `color` to tint the surface and text with any palette accent.

<Preview align="block" code="&#x22;<Avatar name=\&#x22;Ada Lovelace\&#x22; />\n<Avatar color=\&#x22;brand\&#x22; name=\&#x22;Ada Lovelace\&#x22; />\n<Avatar color=\&#x22;green\&#x22; name=\&#x22;Grace Hopper\&#x22; />\n<Avatar color=\&#x22;purple\&#x22; name=\&#x22;Zendaya\&#x22; />&#x22;">
  <div className="flex flex-wrap gap-2">
    <Avatar name="Neutral" />

    {COLORS.map((c) => (
          <Avatar key={c} color={c} name={c} />
        ))}
  </div>
</Preview>

## Auto-color from name or initials [#auto-color-from-name-or-initials]

Set `color="initials"` or `color="name"` to skip picking a color by hand — it's deterministically hashed instead, so the same input always resolves to the same accent.

* `"initials"` hashes the *derived initials*: two different people who happen to share initials get the **same** color, useful for visual grouping.
* `"name"` hashes the *full name* directly: the same two people almost always get **different** colors, useful for per-person distinction even when initials collide.

<Preview align="block" code="&#x22;{/* \&#x22;Ada Lovelace\&#x22; and \&#x22;Alex Lambert\&#x22; both have the initials \&#x22;AL\&#x22; */}\n<Avatar color=\&#x22;initials\&#x22; name=\&#x22;Ada Lovelace\&#x22; />\n<Avatar color=\&#x22;initials\&#x22; name=\&#x22;Alex Lambert\&#x22; />\n{/* same two names, but color=\&#x22;name\&#x22; tells them apart */}\n<Avatar color=\&#x22;name\&#x22; name=\&#x22;Ada Lovelace\&#x22; />\n<Avatar color=\&#x22;name\&#x22; name=\&#x22;Alex Lambert\&#x22; />&#x22;">
  <div className="flex flex-wrap items-center gap-3">
    <Avatar color="initials" name="Ada Lovelace" />

    <Avatar color="initials" name="Alex Lambert" />

    <Avatar color="name" name="Ada Lovelace" />

    <Avatar color="name" name="Alex Lambert" />
  </div>
</Preview>

`palette` restricts (or extends) which colors the hash can land on — it defaults to `AVATAR_PALETTE`, a curated 9-color set that excludes `brand` (the kit's own primary/CTA identity color) and `neutral` (too muted to read as a distinct accent).

```tsx
import { Avatar, AVATAR_PALETTE } from '@42-central/ui-react/avatar';

<Avatar color="name" name="Ada Lovelace" palette={['blue', 'purple']} />
<Avatar color="name" name="Ada Lovelace" palette={[...AVATAR_PALETTE, 'brand']} />
```

## Sizes & radius [#sizes--radius]

`size` is the kit's shared `xs`–`xl` scale. `radius` defaults to `full` — unlike [`ThemeIcon`](/docs/theme-icon), which defaults to `md` — because an avatar reads as circular by default.

<Preview align="block" code="&#x22;<Avatar size=\&#x22;xs\&#x22; name=\&#x22;Ada Lovelace\&#x22; />\n<Avatar size=\&#x22;sm\&#x22; name=\&#x22;Ada Lovelace\&#x22; />\n<Avatar size=\&#x22;md\&#x22; name=\&#x22;Ada Lovelace\&#x22; />\n<Avatar size=\&#x22;lg\&#x22; name=\&#x22;Ada Lovelace\&#x22; />\n<Avatar size=\&#x22;xl\&#x22; name=\&#x22;Ada Lovelace\&#x22; />&#x22;">
  <div className="flex flex-wrap items-end gap-3">
    <Avatar size="xs" name="Ada Lovelace" />

    <Avatar size="sm" name="Ada Lovelace" />

    <Avatar size="md" name="Ada Lovelace" />

    <Avatar size="lg" name="Ada Lovelace" />

    <Avatar size="xl" name="Ada Lovelace" />
  </div>
</Preview>

<Preview align="block" code="&#x22;<Avatar radius=\&#x22;xs\&#x22; color=\&#x22;pink\&#x22; name=\&#x22;Ada Lovelace\&#x22; />\n<Avatar radius=\&#x22;md\&#x22; color=\&#x22;pink\&#x22; name=\&#x22;Ada Lovelace\&#x22; />\n<Avatar radius=\&#x22;xl\&#x22; color=\&#x22;pink\&#x22; name=\&#x22;Ada Lovelace\&#x22; />\n<Avatar radius=\&#x22;full\&#x22; color=\&#x22;pink\&#x22; name=\&#x22;Ada Lovelace\&#x22; />&#x22;">
  <div className="flex flex-wrap items-center gap-3">
    <Avatar radius="xs" color="pink" name="Ada Lovelace" />

    <Avatar radius="md" color="pink" name="Ada Lovelace" />

    <Avatar radius="xl" color="pink" name="Ada Lovelace" />

    <Avatar radius="full" color="pink" name="Ada Lovelace" />
  </div>
</Preview>

## Avatar.Group [#avatargroup]

`Avatar.Group` overlaps a row (or, with `orientation="vertical"`, a column) of standalone `Avatar`s, the classic stacked-avatars look — each one gets a transparent notch cut into it (via `mask-image`) exactly where its successor overlaps it, so the separation is true see-through space rather than a painted border, and it reads correctly over any page background. It's pure layout — it doesn't resize or restyle its children, so set `size`/`color` per `Avatar`. `spacing` (the shared size scale) controls how much they overlap.

<Preview code="&#x22;<Avatar.Group>\n  <Avatar src=\&#x22;https://i.pravatar.cc/150?img=12\&#x22; name=\&#x22;Ada Lovelace\&#x22; />\n  <Avatar name=\&#x22;Grace Hopper\&#x22; color=\&#x22;teal\&#x22; />\n  <Avatar name=\&#x22;Zendaya\&#x22; color=\&#x22;purple\&#x22; />\n  <Avatar color=\&#x22;neutral\&#x22;>+4</Avatar>\n</Avatar.Group>&#x22;">
  <AvatarGroupExample />
</Preview>

There's no built-in overflow counter — compose one yourself as a trailing `Avatar` (as above), the same way Mantine's own docs demonstrate it.

<Preview code="&#x22;<Avatar.Group spacing=\&#x22;xs\&#x22;>...</Avatar.Group>\n<Avatar.Group spacing=\&#x22;xl\&#x22;>...</Avatar.Group>&#x22;">
  <AvatarGroupSpacingExample />
</Preview>

The notch matches each avatar's own `radius`, not just the default circle — a rounded-square avatar gets a true rounded-rect cutout that follows its neighbor's actual silhouette, not a circular bite:

<Preview code="&#x22;<Avatar.Group>\n  <Avatar radius=\&#x22;md\&#x22; src=\&#x22;https://i.pravatar.cc/150?img=12\&#x22; name=\&#x22;Ada Lovelace\&#x22; />\n  <Avatar radius=\&#x22;md\&#x22; name=\&#x22;Grace Hopper\&#x22; color=\&#x22;teal\&#x22; />\n  <Avatar radius=\&#x22;md\&#x22; name=\&#x22;Zendaya\&#x22; color=\&#x22;purple\&#x22; />\n  <Avatar radius=\&#x22;md\&#x22; color=\&#x22;neutral\&#x22;>+4</Avatar>\n</Avatar.Group>&#x22;">
  <AvatarGroupRadiusExample />
</Preview>

`orientation="vertical"` stacks them as a column instead, each one overlapping the one above it and the notch cut at the bottom edge. A column runs top-to-bottom in either text direction, so `dir` doesn't affect it:

<Preview code="&#x22;<Avatar.Group orientation=\&#x22;vertical\&#x22;>\n  <Avatar src=\&#x22;https://i.pravatar.cc/150?img=12\&#x22; name=\&#x22;Ada Lovelace\&#x22; />\n  <Avatar name=\&#x22;Grace Hopper\&#x22; color=\&#x22;teal\&#x22; />\n  <Avatar name=\&#x22;Zendaya\&#x22; color=\&#x22;purple\&#x22; />\n  <Avatar color=\&#x22;neutral\&#x22;>+4</Avatar>\n</Avatar.Group>&#x22;">
  <AvatarGroupVerticalExample />
</Preview>

## API [#api]

### Avatar [#avatar]

<TypeTable
  type="{
  src: {
    type: &#x22;string&#x22;,
    description:
      &#x22;Image source. Falls back automatically when unset or on load error.&#x22;,
  },
  alt: {
    type: &#x22;string&#x22;,
    description: &#x22;Alt text for the image.&#x22;,
  },
  name: {
    type: &#x22;string&#x22;,
    description:
      'Full name to derive initials/color from (e.g. &#x22;Ada Lovelace&#x22; → &#x22;AL&#x22;) when there\'s no image and no explicit children.',
  },
  display: {
    type: &#x22;'name' | 'initials'&#x22;,
    default: &#x22;'initials'&#x22;,
    description:
      &#x22;Which name-derived form the computed fallback shows: two-letter initials, or a single leading letter of name.&#x22;,
  },
  children: {
    type: &#x22;ReactNode&#x22;,
    description:
      &#x22;Fallback content — shown until the image loads, or permanently with no src. Overrides the name/display-derived content.&#x22;,
  },
  color: {
    type: &#x22;'brand' | 'neutral' | 'red' | 'orange' | 'yellow' | 'green' | 'teal' | 'cyan' | 'blue' | 'purple' | 'pink' | 'name' | 'initials' | (string & {})&#x22;,
    description:
      &#x22;'name' / 'initials' hash `name` (or its derived initials) into a pick from `palette`. Any other value is a literal accent. Neutral gray when unset.&#x22;,
  },
  palette: {
    type: &#x22;Color[]&#x22;,
    default: &#x22;AVATAR_PALETTE&#x22;,
    description:
      'Colors eligible for color=&#x22;name&#x22; / color=&#x22;initials&#x22;\'s hash. Ignored otherwise.',
  },
  size: {
    type: &#x22;'xs' | 'sm' | 'md' | 'lg' | 'xl'&#x22;,
    default: &#x22;'md'&#x22;,
    description: &#x22;Diameter, text scale, and icon scale.&#x22;,
  },
  radius: {
    type: &#x22;'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'full'&#x22;,
    default: &#x22;'full'&#x22;,
    description: &#x22;Corner radius.&#x22;,
  },
  classNames: {
    type: &#x22;{ root?, image?, fallback? }&#x22;,
    description: &#x22;Per-part class overrides.&#x22;,
  },
  testId: {
    type: &#x22;string&#x22;,
    description:
      &#x22;Renders as `data-testid` on the root element. See [Testing](/docs/testing).&#x22;,
  },
}"
/>

No `asChild` — `children` is already repurposed as fallback content, which conflicts with Ark's "single child to render as" requirement for polymorphism (the same reasoning [`Skeleton`](/docs/skeleton) documents for its own opt-out).

### Avatar.Group [#avatargroup-1]

<TypeTable
  type="{
  spacing: {
    type: &#x22;'xs' | 'sm' | 'md' | 'lg' | 'xl'&#x22;,
    default: &#x22;'md'&#x22;,
    description:
      &#x22;Overlap amount between avatars — larger sizes overlap by more.&#x22;,
  },
  orientation: {
    type: &#x22;'horizontal' | 'vertical'&#x22;,
    default: &#x22;'horizontal'&#x22;,
    description:
      &#x22;Stack direction: a row (following `dir`), or a top-to-bottom column. Also set as `data-orientation` on the root.&#x22;,
  },
  testId: {
    type: &#x22;string&#x22;,
    description:
      &#x22;Renders as `data-testid` on the group's root `<div>` — its own, separate from any child `Avatar`'s `testId`. See [Testing](/docs/testing).&#x22;,
  },
}"
/>

`Avatar.Group` forwards remaining props (incl. `asChild`) to its root `div`.

## Accessibility [#accessibility]

Pass `alt` describing the person or entity whenever `src` is set — it's forwarded straight to the underlying `<img>`. A text-only `Avatar` (initials or icon fallback) renders as plain content with no implicit role; wrap it with your own `aria-label` if it needs to announce more than its visible text.
