# Avatar

A person, as a circle, with initials until the image lands.

- Group: Display
- Import: `import { Avatar } from '@misoto22/folio'`
- Page: https://ui.misoto22.com/components/avatar/

## Anatomy

- **Circle** (required) — The Radix root: a --rule hairline over --stone, overflow hidden, and one of three fixed squares — 28px, 36px or 48px. It carries role="img" and alt as its own name, because it is the one element in here that is always rendered.
- **Image** — Rendered only when src is given, object-cover so a portrait crops to the circle instead of distorting. Its own alt is empty on purpose — the circle around it is what names the person, and a second name here is the same person read twice.
- **Initials** — The Radix fallback: mono, uppercase, --ink-3-aa, and aria-hidden. Radix shows it while the image is loading and once it has failed, which is why it does not flash on every render the way a hand-rolled onError swap does.

## Best practices

### Do

- Write alt for the person, not for the row: the circle carries it whether or not a photograph ever arrives, so a list where photographs are optional announces every person rather than every second one.
- Pass initials that hold up on their own: fallback is required because the image is the optional half, and most rows of a real list render as this element rather than as a photograph.
- Let Radix own the swap rather than reaching for onError — it flips to the fallback only once the image has actually failed, which is what keeps the initials from appearing for a frame before the cache answers.

### Don’t

- The avatar is not the control. sm is 28px and md is 36px, both under the 44px pointer-target floor (WCAG 2.5.8), and the root is a <span> nothing has made focusable — an account menu made by hanging onClick on it is unreachable and undersized at once.
- children is deliberately omitted from the props: the image and the fallback are the only two things that go in the circle, and the root is overflow-hidden, so a presence dot placed inside it is clipped by the very border that makes it round.

## Accessibility

- alt names the circle itself, as role="img", so an avatar with no photograph still says who it is.
- An empty alt is correct when the name is already printed beside it: the circle then takes no role at all rather than an unnamed one, and leaves the tree entirely.
- The initials are aria-hidden — read aloud beside a name the root already gives, they are noise.

## Avatar

A person, as a circle. Wraps Radix so the fallback appears only after the image has actually failed or is still loading — a hand-rolled `onError` swap flashes the initials on every render before the cache answers. The ROOT carries the accessible name, not the image. `alt` on the image reaches the DOM only when `src` does, and the initials are aria-hidden, so an avatar with no photograph announced nothing at all however carefully `alt` was written — and a user list where photographs are optional is full of them.

### Props

- `src` — `string`.
- `alt` (required) — `string`. Describes the person, not the picture. It names the circle itself rather than the image inside it, because the image is the optional half and most rows of a real list render as initials. Empty string is correct and deliberate when the name is already printed beside the avatar: the circle then leaves the accessibility tree entirely, rather than repeating a name a screen reader has just read.
- `fallback` (required) — `string`. Shown while the image loads and if it never does. Usually initials.
- `size` — `'sm' | 'md' | 'lg'` default `'md'`.

Also accepts: `Omit<ComponentProps<typeof AvatarPrimitive.Root>, 'children'>`.

## Example — sizes

```tsx
import { Avatar } from '@misoto22/folio'

<div className="flex items-center gap-3">
  <Avatar size="sm" alt="" fallback="HC" />
  <Avatar size="md" alt="" fallback="MI" />
  <Avatar size="lg" alt="" fallback="22" />
</div>
```

## Example — a name beside it

```tsx
import { Avatar, Text } from '@misoto22/folio'

<ul className="m-0 flex list-none flex-col gap-4 p-0">
  <li className="flex items-center gap-3">
    <Avatar alt="" fallback="HC" />
    <div className="flex flex-col">
      <Text as="span" size="sm" tone="strong">Henry Chen</Text>
      <Text as="span" size="xs" tone="muted">Design systems</Text>
    </div>
  </li>
  <li className="flex items-center gap-3">
    <Avatar alt="" fallback="RW" />
    <div className="flex flex-col">
      <Text as="span" size="sm" tone="strong">Rui Wang</Text>
      <Text as="span" size="xs" tone="muted">Infrastructure</Text>
    </div>
  </li>
</ul>
```

## Example — inside the control

```tsx
import { Avatar, Button } from '@misoto22/folio'

<div className="flex flex-wrap items-center gap-3">
  <Button variant="secondary">
    <Avatar size="sm" alt="" fallback="HC" />
    Henry Chen
  </Button>
  <Button variant="ghost">
    <Avatar size="sm" alt="" fallback="RW" />
    Switch account
  </Button>
</div>
```
