Avatar
User or entity portrait with graceful image fallback. Sizes, presence badges, and overlapping groups.
Overview
Avatar is the user or entity portrait primitive. It wraps Radix Avatar, which handles the image-load lifecycle for you: while the source loads, AvatarFallback renders; if the load errors or src is missing, the fallback stays. The Avatar never renders as a broken image or empty circle.
Three sizes ship on the root (sm, default, lg) and propagate to subcomponents via data-size. For richer compositions, drop in AvatarBadge for a presence dot or status indicator, and use AvatarGroup plus AvatarGroupCount for overlapping stacks.
Preview
'use client';import { Avatar, AvatarFallback, AvatarImage } from '@gremorie/rx-display';export function AvatarPreview() { return ( <div className="flex items-center gap-3"> <Avatar> <AvatarImage src="https://avatars.githubusercontent.com/u/41934312?v=4" alt="@kalvner" /> <AvatarFallback>KA</AvatarFallback> </Avatar> <Avatar> <AvatarFallback>KA</AvatarFallback> </Avatar> <Avatar> <AvatarFallback>NG</AvatarFallback> </Avatar> </div> );}Anatomy
Avatar root circle; sets size via data-size
├─ AvatarImage the portrait; hidden until loaded
├─ AvatarFallback initials/icon shown while loading or on error
└─ AvatarBadge small status dot anchored bottom-right
AvatarGroup overlapping -space-x-2 stack of Avatars
├─ Avatar each stacked portrait (see above)
└─ AvatarGroupCount "+N" overflow chipInstallation
bash npx gremorie@latest add rx-avatar bash pnpm dlx gremorie@latest add rx-avatar bash yarn dlx gremorie@latest add rx-avatar bash bunx --bun gremorie@latest add rx-avatar Usage
import {
Avatar,
AvatarImage,
AvatarFallback,
} from "@gremorie/rx-display";
export function Example() {
return (
<Avatar>
<AvatarImage src="https://github.com/kalvner.png" alt="@kalvner" />
<AvatarFallback>KA</AvatarFallback>
</Avatar>
);
}The Angular edition of this component ships from source today (see the workbench for the side-by-side); its registry entry is coming next.
API
<Avatar>
Root container. Wraps Radix Avatar.Root.
| Prop | Type | Default | Description |
|---|---|---|---|
size | "sm" | "default" | "lg" | "default" | Sets the root dimensions (size-6, size-8, size-10) and propagates to subcomponents via data-size. |
className | string | - | Extra classes. Use to override the default size-* when you need an in-between or larger size. |
For sizes beyond lg, pass an explicit size-12 or larger via className.
<AvatarImage>
The image. Wraps Radix Avatar.Image. Forwards all img props including src, alt, onLoadingStatusChange.
| Prop | Type | Default | Description |
|---|---|---|---|
src | string | - | Image URL. Required for the image to render. |
alt | string | - | Alt text. Required for accessibility. |
<AvatarFallback>
The fallback content (typically initials). Wraps Radix Avatar.Fallback.
| Prop | Type | Default | Description |
|---|---|---|---|
delayMs | number | - | Delays the fallback render to avoid a flash while the image loads. |
<AvatarBadge>
Presence dot or status indicator. Positions absolutely in the bottom-right corner of the Avatar with a ring matching the page background.
Sizes adapt automatically to the parent Avatar's data-size - the badge stays proportional.
<AvatarGroup>
Container for overlapping Avatars. Applies -space-x-2 and a 2px ring on each child Avatar so they read as a stack.
<AvatarGroupCount>
Trailing "+N" indicator for hidden Avatars in a group. Inherits the group's size from group-has-data-[size=*]/avatar-group selectors.
Composition
<Avatar>is the container - always renders a circle.- Inside Avatar: place
<AvatarImage>first, then<AvatarFallback>as a safety net. Both must be siblings; Radix coordinates the lifecycle. <AvatarBadge>is optional and absolute-positioned - drop it as the last child ofAvatar.- Groups: wrap multiple
Avatars in<AvatarGroup>and end with<AvatarGroupCount>if you have overflow.
Variations
Sizes
'use client';import { Avatar, AvatarFallback, AvatarImage } from '@gremorie/rx-display';export function AvatarSizesPreview() { return ( <div className="flex items-center gap-3"> <Avatar size="sm"> <AvatarImage src="https://avatars.githubusercontent.com/u/41934312?v=4" alt="@kalvner" /> <AvatarFallback>SM</AvatarFallback> </Avatar> <Avatar> <AvatarImage src="https://avatars.githubusercontent.com/u/41934312?v=4" alt="@kalvner" /> <AvatarFallback>MD</AvatarFallback> </Avatar> <Avatar size="lg"> <AvatarImage src="https://avatars.githubusercontent.com/u/41934312?v=4" alt="@kalvner" /> <AvatarFallback>LG</AvatarFallback> </Avatar> </div> );}Three sizes ship on the root: sm (size-6), default (size-8), and lg (size-10). The size propagates to subcomponents via data-size.
Fallback only
'use client';import { Avatar, AvatarFallback, AvatarImage } from '@gremorie/rx-display';export function AvatarFallbackPreview() { return ( <div className="flex items-center gap-3"> <Avatar> <AvatarImage src="/broken-image.png" alt="@kalvner" /> <AvatarFallback>KA</AvatarFallback> </Avatar> <Avatar> <AvatarFallback>NG</AvatarFallback> </Avatar> <Avatar> <AvatarFallback>SP</AvatarFallback> </Avatar> </div> );}When the image source is missing or fails to load, AvatarFallback renders automatically - typically initials. The Avatar never shows a broken image.
Overlapping group
'use client';import { Avatar, AvatarFallback, AvatarGroup, AvatarGroupCount,} from '@gremorie/rx-display';export function AvatarGroupPreview() { return ( <AvatarGroup> <Avatar> <AvatarFallback>KA</AvatarFallback> </Avatar> <Avatar> <AvatarFallback>NG</AvatarFallback> </Avatar> <Avatar> <AvatarFallback>SP</AvatarFallback> </Avatar> <AvatarGroupCount>+3</AvatarGroupCount> </AvatarGroup> );}AvatarGroup applies -space-x-2 and a background ring so the avatars read as a stack. End with AvatarGroupCount to show overflow.
With presence badge
'use client';import { Avatar, AvatarBadge, AvatarFallback, AvatarImage,} from '@gremorie/rx-display';export function AvatarBadgePreview() { return ( <Avatar size="lg"> <AvatarImage src="https://avatars.githubusercontent.com/u/41934312?v=4" alt="@kalvner" /> <AvatarFallback>KA</AvatarFallback> <AvatarBadge className="bg-emerald-500" /> </Avatar> );}AvatarBadge positions absolutely in the bottom-right corner and adapts its size to the parent Avatar's data-size.
Accessibility
AvatarImagerequiresalt: pass the user or entity name. Screen readers announce the alt; the fallback is hidden from AT while the image is present.- Fallback content: when the image fails, the fallback text (typically initials) becomes the announced label. Keep it meaningful - "KA" announces as "K A"; use the full name in
aria-labelon the Avatar root if initials are too cryptic. - Decorative use: when an Avatar is purely decorative (e.g. in a marketing illustration), pass
alt=""onAvatarImageand addaria-hidden="true"on the Avatar root so AT skips it. - Presence badges:
AvatarBadgeis a<span>with no semantics. Convey presence through context (e.g. a sibling tooltip or text), not color alone. - Group counts:
AvatarGroupCountannounces as "+3" or whatever you put inside - wrap with text like "and 3 more" for clearer screen-reader output.