# Avatar

> Avatars show a person as a photo, initials or a person glyph, alone or in a group.

Source: /docs/components/avatar

```tsx
import { Avatar, AvatarGroup, AvatarGroupCount } from '@aksornproject/aksara-ui'
```

## Content

The Avatar shows the photo once `src` loads. Until then, or if it fails, it shows the `fallback` text. Without `fallback` it draws a person glyph.

`fallback` renders verbatim, so pass the initials you want to show. `children` replace the photo and the fallback.

```tsx
import { Avatar } from '@aksornproject/aksara-ui'

const photo = `data:image/svg+xml,${encodeURIComponent(
  '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" fill="#9ec5e8"/><circle cx="32" cy="26" r="12" fill="#f1c27d"/><circle cx="32" cy="66" r="24" fill="#3d5a80"/></svg>',
)}`

export default function AvatarContent() {
  return (
    <>
      <Avatar size="medium" src={photo} alt="Somchai Prasert" fallback="SP" />
      <Avatar size="medium" fallback="NK" />
      <Avatar size="medium" />
    </>
  )
}
```

## Sizes

Five sizes, from `tiny` (20px) to `large` (128px). `xsmall` (24px) is the default. The initials keep the 16px font-size mode, so they never outgrow the circle when an app scales its base font size.

```tsx
import { Avatar } from '@aksornproject/aksara-ui'

export default function AvatarSizes() {
  return (
    <>
      <Avatar size="tiny" fallback="SP" />
      <Avatar size="xsmall" fallback="SP" />
      <Avatar size="small" fallback="SP" />
      <Avatar size="medium" fallback="SP" />
      <Avatar size="large" fallback="SP" />
    </>
  )
}
```

## Variants

`variant` sets the border. `default` has none, `border` draws a 2px subtle border and `dashed` a 2px dashed one.

```tsx
import { Avatar } from '@aksornproject/aksara-ui'

export default function AvatarVariants() {
  return (
    <>
      <Avatar size="medium" fallback="NK" />
      <Avatar size="medium" variant="border" fallback="NK" />
      <Avatar size="medium" variant="dashed" />
    </>
  )
}
```

## Status

`status` adds a `success`, `neutral` or `error` dot on the edge of the circle. The dot is hidden from assistive technology, so put the status in `alt` as well.

```tsx
import { Avatar } from '@aksornproject/aksara-ui'

const portrait = (background: string, skin: string, shirt: string) =>
  `data:image/svg+xml,${encodeURIComponent(
    `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" fill="${background}"/><circle cx="32" cy="26" r="12" fill="${skin}"/><circle cx="32" cy="66" r="24" fill="${shirt}"/></svg>`,
  )}`

export default function AvatarStatus() {
  return (
    <>
      <Avatar
        size="medium"
        src={portrait('#9ec5e8', '#f1c27d', '#3d5a80')}
        alt="Somchai Prasert, online"
        status="success"
      />
      <Avatar
        size="medium"
        src={portrait('#f4b6c2', '#c68642', '#6d597a')}
        alt="Nicha Kanchana, away"
        status="neutral"
      />
      <Avatar
        size="medium"
        src={portrait('#b5e48c', '#8d5524', '#1d3557')}
        alt="Arthit Wong, sync failed"
        status="error"
      />
    </>
  )
}
```

## Disabled and loading

`disabled` dims the Avatar and sets `aria-disabled`. `loading` shows the skeleton fill, hides the content and sets `aria-busy`. The Avatar also shows the skeleton while its image loads.

```tsx
import { Avatar } from '@aksornproject/aksara-ui'

export default function AvatarStates() {
  return (
    <>
      <Avatar size="medium" fallback="SP" disabled />
      <Avatar size="medium" fallback="SP" loading />
    </>
  )
}
```

## Group

`AvatarGroup` draws a white ring around each child and places the rings edge to edge. Its `size` reaches every child that does not set its own.

The group does not count or slice. Render the visible Avatars yourself and an `AvatarGroupCount` with the overflow.

```tsx
import { Avatar, AvatarGroup, AvatarGroupCount } from '@aksornproject/aksara-ui'

const portrait = (background: string, skin: string, shirt: string) =>
  `data:image/svg+xml,${encodeURIComponent(
    `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" fill="${background}"/><circle cx="32" cy="26" r="12" fill="${skin}"/><circle cx="32" cy="66" r="24" fill="${shirt}"/></svg>`,
  )}`

const members = [
  {
    id: 1,
    name: 'Somchai Prasert',
    photo: portrait('#9ec5e8', '#f1c27d', '#3d5a80'),
  },
  {
    id: 2,
    name: 'Nicha Kanchana',
    photo: portrait('#f4b6c2', '#c68642', '#6d597a'),
  },
  {
    id: 3,
    name: 'Arthit Wong',
    photo: portrait('#b5e48c', '#8d5524', '#1d3557'),
  },
]

export default function AvatarOverflow() {
  return (
    <AvatarGroup size="small">
      {members.map((member) => (
        <Avatar key={member.id} src={member.photo} alt={member.name} />
      ))}
      <AvatarGroupCount>+4</AvatarGroupCount>
    </AvatarGroup>
  )
}
```

## Interactive

`render` swaps the root element. Rendered as a `button` or a link, the Avatar shows a hover overlay and the focus ring. A plain Avatar shows neither.

```tsx
import { Avatar } from '@aksornproject/aksara-ui'

export default function AvatarInteractive() {
  return (
    <Avatar
      size="medium"
      fallback="SP"
      aria-label="Open Somchai Prasert's profile"
      render={<button type="button" />}
    />
  )
}
```

## Accessibility

- `alt` names the photo. It falls back to `fallback`, then to an empty string.
- The status dot is `aria-hidden`. Put the status in `alt` or in nearby text.
- An interactive Avatar needs an accessible name. With a photo, `alt` gives it one. With initials, pass `aria-label`.
- `disabled` sets `aria-disabled`. `loading` and a loading image set `aria-busy`.

## API

### Avatar

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `children` | `ReactNode` |  | Replaces the image and the fallback. |
| `className` | `string \| ((state: AvatarRootState) => string \| undefined)` |  | CSS class applied to the element, or a function that returns a class based on the component's state. |
| `render` | `ComponentRenderFn<HTMLProps, AvatarRootState> \| React.ReactElement<unknown, string \| React.JSXElementConstructor<any>>` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. |
| `style` | `React.CSSProperties \| ((state: AvatarRootState) => React.CSSProperties \| undefined)` |  | Style applied to the element, or a function that returns a style object based on the component's state. |
| `src` | `string` |  | Image URL. The Avatar shows the skeleton until the image loads. |
| `alt` | `string` |  | Defaults to `fallback`, then `''`. |
| `fallback` | `string` |  | Text shown verbatim while no image is loaded. Without it the Avatar draws a person glyph. |
| `variant` | `"border" \| "dashed" \| "default"` | `'default'` | Border style. `default` has no border. |
| `size` | `"large" \| "medium" \| "small" \| "tiny" \| "xsmall"` |  | Defaults to the `AvatarGroup` size, then `'xsmall'` (24px). |
| `status` | `"error" \| "neutral" \| "success"` |  | Shows a status dot. Put the status in the accessible name too. |
| `disabled` | `boolean` | `false` | Dims the Avatar and sets `aria-disabled`. |
| `loading` | `boolean` | `false` | Shows the skeleton fill and hides the content. The Avatar also shows it while its image loads. |
| `dataTestId` | `string` |  | `data-testid` on the inner wrapper. |

### AvatarGroup

| Prop | Type | Description |
| --- | --- | --- |
| `size` | `"large" \| "medium" \| "small" \| "tiny" \| "xsmall"` | Size for every child that does not set its own. |

### AvatarGroupCount

| Prop | Type | Description |
| --- | --- | --- |
| `className` | `string \| ((state: AvatarRootState) => string \| undefined)` | CSS class applied to the element, or a function that returns a class based on the component's state. |
| `render` | `ComponentRenderFn<HTMLProps, AvatarRootState> \| React.ReactElement<unknown, string \| React.JSXElementConstructor<any>>` | Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. |
| `style` | `React.CSSProperties \| ((state: AvatarRootState) => React.CSSProperties \| undefined)` | Style applied to the element, or a function that returns a style object based on the component's state. |
| `size` | `"large" \| "medium" \| "small" \| "tiny" \| "xsmall"` | Defaults to the `AvatarGroup` size, then `'xsmall'`. |