---
title: Avatar
description: User avatar with image, initials, or status
visibility: guest
draft: false
---

# Avatar

A user profile image with automatic fallback to initials or a default icon. Avatars support five sizes, two shapes, and optional status indicators.

## Basic Usage

:::preview{title="With image"}
<x-wirekit::avatar src="/placeholder/80x80?bg=4f46e5&fg=ffffff&label=JS&gradient=none" alt="Jane Smith" />
:::

:::preview{title="With initials"}
<x-wirekit::avatar initials="JS" alt="Jane Smith" />
:::

:::preview{title="Default fallback icon"}
<x-wirekit::avatar alt="Anonymous user" />
:::

## Fallback Chain

The avatar tries each fallback in order:

1. **Image** (`src` prop) — rendered as `<img>`
2. **Initials** (`initials` prop) — centered text
3. **Default icon** — generic user silhouette SVG

## Sizes

:::preview{title="All sizes"}
<x-wirekit::avatar size="xs" initials="XS" />
<x-wirekit::avatar size="sm" initials="SM" />
<x-wirekit::avatar size="md" initials="MD" />
<x-wirekit::avatar size="lg" initials="LG" />
<x-wirekit::avatar size="xl" initials="XL" />
:::

## Shapes

:::preview{title="Circle and square"}
<x-wirekit::avatar shape="circle" initials="JD" size="lg" />
<x-wirekit::avatar shape="square" initials="JD" size="lg" />
:::

## Status Indicators

Add a status dot to indicate user presence. The dot sits on the bottom-right corner with a ring matching the page background:

:::preview{title="Status dots (default)"}
<x-wirekit::avatar initials="ON" status="online" size="lg" />
<x-wirekit::avatar initials="BS" status="busy" size="lg" />
<x-wirekit::avatar initials="AW" status="away" size="lg" />
<x-wirekit::avatar initials="OF" status="offline" size="lg" />
:::

### Full Status Ring

Set `status-variant="ring"` to replace the corner dot with a colored ring that surrounds the entire avatar, separated from the image by a thin gap in the page background. This produces a "double ring" presence indicator similar to Slack, Discord or iMessage — useful when you want the status to be visible at a glance without hunting for a tiny dot:

:::preview{title="Status ring — all four states"}
<x-wirekit::avatar initials="ON" status="online" status-variant="ring" size="lg" />
<x-wirekit::avatar initials="BS" status="busy" status-variant="ring" size="lg" />
<x-wirekit::avatar initials="AW" status="away" status-variant="ring" size="lg" />
<x-wirekit::avatar initials="OF" status="offline" status-variant="ring" size="lg" />
:::

The ring scales subtly with avatar size so it stays visually balanced on every size variant:

:::preview{title="Status ring across sizes"}
<x-wirekit::avatar initials="XS" status="online" status-variant="ring" size="xs" />
<x-wirekit::avatar initials="SM" status="online" status-variant="ring" size="sm" />
<x-wirekit::avatar initials="MD" status="online" status-variant="ring" size="md" />
<x-wirekit::avatar initials="LG" status="online" status-variant="ring" size="lg" />
<x-wirekit::avatar initials="XL" status="online" status-variant="ring" size="xl" />
:::

When `status-variant="ring"`, the corner dot is omitted — the colored ring on the container already conveys the presence state, and stacking both would be visually noisy. The `role="status"` and `aria-label` move from the dot `<span>` onto the avatar root so screen readers still announce the state once.

## Width & Layout

Avatar dimensions are fixed by the `size` prop (`sm` = 32px, `md` = 40px, `lg` = 48px, `xl` = 64px). The avatar is always a perfect circle.

## Deterministic Color From Initials

Add `from-initials` to derive a stable background color from the initials hash — the same person always gets the same color. The palette pairs an AA-contrast background with white text and is theme-independent.

:::preview{title="Avatars colored from initials"}
<x-wirekit::row gap="sm" wrap>
    <x-wirekit::avatar initials="AB" from-initials />
    <x-wirekit::avatar initials="MP" from-initials />
    <x-wirekit::avatar initials="LK" from-initials />
    <x-wirekit::avatar initials="SR" from-initials />
</x-wirekit::row>
:::

The same palette is available in PHP, so a custom chip or inline badge can match an avatar
without rendering one:

```php
use Pushery\WireKit\WireKit;

// Returns ['bg' => 'oklch(...)', 'fg' => '#fff'] for the same initials the component hashes.
$palette = WireKit::avatarPaletteFor('AB');
```

## With Name & Detail

Compose an avatar with a name and a secondary line (role, email, handle) using
[Row](/components/row) and [Stack](/components/stack) — the canonical "user
identity" cell for menus, tables, and comment headers.

:::preview{title="Avatar with name and detail"}
<x-wirekit::row gap="sm" align="center">
    <x-wirekit::avatar initials="JD" from-initials />
    <x-wirekit::stack gap="none">
        <x-wirekit::text weight="semibold">Jane Doe</x-wirekit::text>
        <x-wirekit::text variant="muted" size="sm">Product Designer</x-wirekit::text>
    </x-wirekit::stack>
</x-wirekit::row>
:::

## Avatar Group

Stack multiple avatars into an overlapping group with `<x-wirekit::avatar.group>`.
Each avatar is ringed in the surface color so the discs read as distinct. Set
`:remaining` for a trailing "+N" overflow chip, and `label` for the group's
accessible name. Match the group's `size` to the avatars you place inside it.

:::preview{title="Overlapping avatar group with overflow count"}
<x-wirekit::avatar.group label="5 collaborators" :remaining="2">
    <x-wirekit::avatar initials="AB" from-initials />
    <x-wirekit::avatar initials="MP" from-initials />
    <x-wirekit::avatar initials="LK" from-initials />
</x-wirekit::avatar.group>
:::

:::preview{title="Avatar group sizes"}
<x-wirekit::stack gap="md">
    <x-wirekit::avatar.group size="sm" label="Small team">
        <x-wirekit::avatar size="sm" initials="AB" from-initials />
        <x-wirekit::avatar size="sm" initials="MP" from-initials />
        <x-wirekit::avatar size="sm" initials="LK" from-initials />
    </x-wirekit::avatar.group>
    <x-wirekit::avatar.group size="lg" label="Large team" :remaining="4">
        <x-wirekit::avatar size="lg" initials="AB" from-initials />
        <x-wirekit::avatar size="lg" initials="MP" from-initials />
    </x-wirekit::avatar.group>
</x-wirekit::stack>
:::

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `src` | string\|null | `null` | Image URL |
| `alt` | string\|null | `null` | Accessible name (for images AND initials/icon fallbacks) |
| `initials` | string\|null | `null` | Text shown when no `src` is provided |
| `size` | string | `'md'` | `xs`, `sm`, `md`, `lg`, `xl` |
| `shape` | string | `'circle'` | `circle`, `square` |
| `status` | string\|null | `null` | `online`, `busy`, `away`, `offline` |
| `scope` | string\|null | `null` | Scoped personalization name |

### `<x-wirekit::avatar.group>`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `remaining` | int\|null | `null` | Renders a trailing "+N" overflow chip when greater than 0 |
| `size` | string | `'md'` | Sizes the overflow chip to match the avatars (`xs`–`xl`) |
| `label` | string\|null | `null` | Accessible name for the group |
| `scope` | string\|null | `null` | Scoped personalization name |

## Accessibility

- **Always provide an `alt` prop.** For `<img>` avatars, this becomes the `alt` attribute. For initials/icon fallbacks, it's rendered as visually hidden text (`sr-only`) so screen readers announce the person's name — not just their initials.
- **Status indicators** use `role="status"` + `aria-label` so screen readers announce the state ("Online", "Busy", etc.).
- **Initials are marked `aria-hidden="true"`** when an `alt` is provided, preventing duplicate announcements.

### Accessibility examples

```blade
{{-- Good: clear identity --}}
<x-wirekit::avatar src="/users/jane.jpg" alt="Jane Smith" />

{{-- Good: name announced via alt, initials hidden --}}
<x-wirekit::avatar initials="JS" alt="Jane Smith" />

{{-- Decorative (e.g. in a list with visible name next to it): --}}
<x-wirekit::avatar initials="JS" />
```

## Keyboard Interaction

This component is purely presentational and does not respond to keyboard input.

## Pitfalls

- **Don't use an avatar without `alt`.** Decorative use is fine with `alt=""`; identifying use needs the person's name in `alt` or it's not announced.

## Design Tokens

| Token | Purpose |
| --- | --- |
| `--color-wk-bg-muted` | Fallback background (initials + icon) |
| `--color-wk-text` | Initials text color |
| `--color-wk-text-muted` | Default icon color |
| `--color-wk-border-subtle` | Avatar border |
| `--color-wk-success` / `--color-wk-warning` / `--color-wk-danger` / `--color-wk-text-muted` | Status colors |
| `--color-wk-bg-elevated` | Status dot ring color |
| `--radius-wk-md` | Square avatar radius |

## Customization

Override defaults in `config/wirekit.php`:

```php
'components' => [
    'avatar' => ['size' => 'lg', 'shape' => 'square'],
],
```
