Avatar
A circular user or entity image with an initials fallback, five sizes, and an overlapping AvatarGroup stack.
- Status
- Since
0.1.0- Accessibility pattern
- image with text fallback
Last updated
Install
Add Avatar from the VegaStack registry. The CLI verifies the item's integrity hash before writing it.
pnpm dlx shadcn@latest add @vegastack/avatarUsage
import { Avatar, AvatarGroup } from "@/components/ui/avatar";
<Avatar
src="https://cdn.example.com/u/ada.webp"
alt="Ada Lovelace"
fallback="AL"
/>;Presentational only.
Avatartakes a fully-resolved, publicsrc. It does not fetch data or resolve storage keys — resolving an R2 (or any CDN) key to a public URL stays app-side, so resolve it before passingsrc. The image only paints once it has loaded; until then (or on error) thefallbackshows, so there is never a broken-image icon.
Anatomy
Avatar is a compound component. Every exported part, with the
data-slot it renders (generated from the canonical source):
Examples
Anatomy
Avatar wraps Base UI Avatar.Root → Avatar.Image → Avatar.Fallback behind a single flat prop
API. AvatarGroup is a layout shell that overlaps its Avatar children.
<AvatarGroup>
<Avatar src={url} alt="…" fallback="AL" /> {/* Root → Image → Fallback */}
<Avatar fallback="+5" /> {/* overflow indicator (no src → fallback) */}
</AvatarGroup>Sizes
xs, sm, default, lg, and xl — the diameter and the fallback text scale together.
Fallback
When src is absent or the image fails to load, the fallback shows — typically 1–2 uppercase
initials, or an icon. Without a fallback, the bare bg-accent circle remains.
Both the no-src path and the image-error path resolve to the same fallback, so a broken or
unreachable src never leaves a broken-image icon — it falls back to the initials (or icon):
Fallback delay
fallbackDelay (ms) waits before swapping in the fallback, avoiding a flash of initials for
fast-loading images — the bare bg-accent circle holds the space until either the image paints or
the delay elapses. It is forwarded to Base UI Avatar.Fallback.
<Avatar src={url} alt="Ada Lovelace" fallback="AL" fallbackDelay={600} />Group
AvatarGroup overlaps its children into a stack and gives each a ring-background so the overlap
reads cleanly on any surface. Add a trailing Avatar with a +N fallback to indicate overflow.
Control overlap density with spacing (tight · default · loose).
The three spacing values side by side — tight tucks each avatar furthest under the previous,
loose overlaps the least:
Playground
Adjust the avatar size and the group's overlap spacing, then copy the generated JSX.
<AvatarGroup>
<Avatar fallback="AL" />
<Avatar fallback="GH" />
<Avatar fallback="+3" />
</AvatarGroup>API Reference
Avatar
| Prop | Type | Default | Description |
|---|---|---|---|
alt | string | — | Accessible alt text describing who/what the avatar represents (usually
the person's name). Pass alt="" only when the avatar image is purely
decorative and an adjacent control/text already names the entity.
Optional because no <img> is rendered when src is absent. |
fallback | React.ReactNode | — | Fallback content shown while the image loads or when it fails / is absent —
typically 1–2 uppercase initials. Falls back to rendering nothing (the bare
bg-accent circle) when omitted. |
fallbackDelay | number | — | How long to wait (ms) before showing the fallback, to avoid a flash for
fast-loading images. Forwarded to Base UI Avatar.Fallback. |
size | "lg" | "md" | "sm" | "xl" | "xs" | 'md' | Diameter of the avatar — also scales the fallback text. |
src | string | — | Image source. Pass a fully-resolved, public URL — this component is
purely presentational and does NOT resolve storage keys. R2 (or any CDN)
key → URL resolution stays app-side; resolve before passing src.
No image source; only the fallback/root renders. |
Data attributes and CSS variables on Avatar
| Attribute | Values |
|---|---|
data-size | mirrors a prop or state value |
data-slot | "avatar" | "avatar-fallback" | "avatar-image" |
AvatarGroup
| Prop | Type | Default | Description |
|---|---|---|---|
spacing | "default" | "loose" | "tight" | 'default' | Overlap density of the stack.
- tight: avatars tuck furthest under one another.
- default: balanced overlap (default).
- loose: minimal overlap. |
Data attributes and CSS variables on AvatarGroup
| Attribute | Values |
|---|---|
data-slot | "avatar-group" |
Accessibility
- When
srcis provided,altis required. Pass the person's or entity's name for meaningful avatars; passalt=""only when adjacent text or the wrapping control already names the entity. - When
srcis absent, no<img>is rendered; the fallback/root carries the visible identity. - The
fallback(initials or icon) is the visible label when no image loads; keep it meaningful (initials of the same name) so the avatar stays identifiable without the picture. Avataris non-interactive by default. When an avatar links to a profile, wrap it in an interactive element (aButton/link) that owns the accessible name and focus ring — don't rely on the image alone.
| Key | Action |
|---|---|
Tab | Moves focus only when the avatar is wrapped in an interactive element (link/button). |
| Contract | States tested |
|---|---|
| Behaviour | default, error, loading, selected |
| Accessibility | native-or-base-ui-semantics, browser-accessibility-test |
| Visual | default, loading, error |