Avatar
User icon with image support and initials fallback. Compose with AvatarGroup for stacks.
Examples
Stacked group
Overlap avatars with AvatarGroup and cap the overflow with a count.
import { Avatar, AvatarFallback, AvatarGroup, AvatarImage } from "@codefast/ui/avatar";
export function AvatarGroupExample() {
return (
<AvatarGroup className="grayscale">
<Avatar>
<AvatarImage src="https://github.com/codefastlabs.png" alt="@codefast" />
<AvatarFallback>CN</AvatarFallback>
</Avatar>
<Avatar>
<AvatarImage
src="https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=128&h=128&fit=crop&q=80"
alt="@leo"
/>
<AvatarFallback>LR</AvatarFallback>
</Avatar>
<Avatar>
<AvatarImage
src="https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=128&h=128&fit=crop&q=80"
alt="@ava"
/>
<AvatarFallback>ER</AvatarFallback>
</Avatar>
</AvatarGroup>
);
}
Badge
Use the AvatarBadge component to add a badge to the avatar. The badge is positioned at the bottom right of the avatar.
import { Avatar, AvatarBadge, AvatarFallback, AvatarImage } from "@codefast/ui/avatar";
export function AvatarWithBadge() {
return (
<Avatar>
<AvatarImage src="https://github.com/codefastlabs.png" alt="@codefast" />
<AvatarFallback>CN</AvatarFallback>
<AvatarBadge className="bg-green-600 dark:bg-green-800" />
</Avatar>
);
}
Badge with Icon
You can also use an icon inside <AvatarBadge>.
import { Avatar, AvatarBadge, AvatarFallback, AvatarImage } from "@codefast/ui/avatar";
import { PlusIcon } from "lucide-react";
export function AvatarBadgeIconExample() {
return (
<Avatar className="grayscale">
<AvatarImage src="https://github.com/codefastlabs.png" alt="@codefast" />
<AvatarFallback>PP</AvatarFallback>
<AvatarBadge>
<PlusIcon />
</AvatarBadge>
</Avatar>
);
}
Basic
A basic avatar component with an image and a fallback.
import { Avatar, AvatarFallback, AvatarImage } from "@codefast/ui/avatar";
export function AvatarBasic() {
return (
<Avatar>
<AvatarImage src="https://github.com/codefastlabs.png" alt="@codefast" className="grayscale" />
<AvatarFallback>CN</AvatarFallback>
</Avatar>
);
}
Dropdown
You can use the Avatar component as a trigger for a dropdown menu.
import { Avatar, AvatarFallback, AvatarImage } from "@codefast/ui/avatar";
import { Button } from "@codefast/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@codefast/ui/dropdown-menu";
export function AvatarDropdown() {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" className="rounded-full">
<Avatar>
<AvatarImage src="https://github.com/codefastlabs.png" alt="codefast" />
<AvatarFallback>CN</AvatarFallback>
</Avatar>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-32">
<DropdownMenuGroup>
<DropdownMenuItem>Profile</DropdownMenuItem>
<DropdownMenuItem>Billing</DropdownMenuItem>
<DropdownMenuItem>Settings</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem variant="destructive">Log out</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
);
}
Avatar Group Count
Use <AvatarGroupCount> to add a count to the group.
import { Avatar, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage } from "@codefast/ui/avatar";
export function AvatarGroupCountExample() {
return (
<AvatarGroup className="grayscale">
<Avatar>
<AvatarImage src="https://github.com/codefastlabs.png" alt="@codefast" />
<AvatarFallback>CN</AvatarFallback>
</Avatar>
<Avatar>
<AvatarImage
src="https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=128&h=128&fit=crop&q=80"
alt="@leo"
/>
<AvatarFallback>LR</AvatarFallback>
</Avatar>
<Avatar>
<AvatarImage
src="https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=128&h=128&fit=crop&q=80"
alt="@ava"
/>
<AvatarFallback>ER</AvatarFallback>
</Avatar>
<AvatarGroupCount>+3</AvatarGroupCount>
</AvatarGroup>
);
}
Avatar Group with Icon
You can also use an icon inside <AvatarGroupCount>.
import { Avatar, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage } from "@codefast/ui/avatar";
import { PlusIcon } from "lucide-react";
export function AvatarGroupCountIconExample() {
return (
<AvatarGroup className="grayscale">
<Avatar>
<AvatarImage src="https://github.com/codefastlabs.png" alt="@codefast" />
<AvatarFallback>CN</AvatarFallback>
</Avatar>
<Avatar>
<AvatarImage
src="https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=128&h=128&fit=crop&q=80"
alt="@leo"
/>
<AvatarFallback>LR</AvatarFallback>
</Avatar>
<Avatar>
<AvatarImage
src="https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=128&h=128&fit=crop&q=80"
alt="@ava"
/>
<AvatarFallback>ER</AvatarFallback>
</Avatar>
<AvatarGroupCount>
<PlusIcon />
</AvatarGroupCount>
</AvatarGroup>
);
}
RTL
Right-to-left layout support for languages such as Arabic and Hebrew.
Translations are AI-generated for demonstration and may be imperfect.
import { Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage } from "@codefast/ui/avatar";
import type { Translations } from "#/features/components-catalog/components/detail/language";
import { useTranslation } from "#/features/components-catalog/components/detail/language-context";
const translations: Translations = {
en: {
dir: "ltr",
values: {
moreUsers: "+3",
},
},
ar: {
dir: "rtl",
values: {
moreUsers: "+٣",
},
},
he: {
dir: "rtl",
values: {
moreUsers: "+3",
},
},
};
export function AvatarRtl() {
const { dir, t } = useTranslation(translations, "ar");
return (
<div className="flex flex-row flex-wrap items-center gap-6 md:gap-12" dir={dir}>
<Avatar>
<AvatarImage src="https://github.com/codefastlabs.png" alt="@codefast" className="grayscale" />
<AvatarFallback>CN</AvatarFallback>
</Avatar>
<Avatar>
<AvatarImage
src="https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=128&h=128&fit=crop&q=80"
alt="@ava"
/>
<AvatarFallback>ER</AvatarFallback>
<AvatarBadge className="bg-green-600 dark:bg-green-800" />
</Avatar>
<AvatarGroup className="grayscale">
<Avatar>
<AvatarImage src="https://github.com/codefastlabs.png" alt="@codefast" />
<AvatarFallback>CN</AvatarFallback>
</Avatar>
<Avatar>
<AvatarImage
src="https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=128&h=128&fit=crop&q=80"
alt="@leo"
/>
<AvatarFallback>LR</AvatarFallback>
</Avatar>
<Avatar>
<AvatarImage
src="https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=128&h=128&fit=crop&q=80"
alt="@ava"
/>
<AvatarFallback>ER</AvatarFallback>
</Avatar>
<AvatarGroupCount>{t.moreUsers}</AvatarGroupCount>
</AvatarGroup>
</div>
);
}
Sizes
Use the size prop to change the size of the avatar.
import { Avatar, AvatarFallback, AvatarImage } from "@codefast/ui/avatar";
export function AvatarSizeExample() {
return (
<div className="flex flex-wrap items-center gap-2 grayscale">
<Avatar size="sm">
<AvatarImage src="https://github.com/codefastlabs.png" alt="@codefast" />
<AvatarFallback>CN</AvatarFallback>
</Avatar>
<Avatar>
<AvatarImage src="https://github.com/codefastlabs.png" alt="@codefast" />
<AvatarFallback>CN</AvatarFallback>
</Avatar>
<Avatar size="lg">
<AvatarImage src="https://github.com/codefastlabs.png" alt="@codefast" />
<AvatarFallback>CN</AvatarFallback>
</Avatar>
</div>
);
}
Anatomy
How the parts nest — every slot the component exposes, in composition order.
Features
- Three sizes (sm, default, lg); AvatarFallback and AvatarBadge scale to match automatically.
- AvatarBadge overlays a status dot or icon at the bottom corner, sized to the avatar via the group data attribute.
- AvatarGroup overlaps avatars with a negative margin; AvatarGroupCount caps the overflow with a +N indicator, both RTL-aware.
API reference
Props for each part of the component. All native element props are also forwarded.
Avatar
size"sm" | "default" | "lg"Diameter of the avatar.
Default
"default"
AvatarImage
AvatarFallback renders in its place when the image is missing or fails to load.
srcstringThe image URL.
altstringAlternative text for the image.
AvatarGroup
childrenReactNodeWrap Avatar elements to overlap them with a negative margin.
AvatarGroupCount
childrenReactNodeThe +N indicator showing how many avatars are hidden from the group.
Accessibility
Built to be keyboard-navigable and screen-reader friendly out of the box.
- Always set a meaningful alt on AvatarImage; use the person’s name.
- AvatarFallback initials are decorative — the name should still exist in alt or nearby text.
- The status badge is decorative; convey the same status in text where it matters.
Guidelines
Conventions that keep usage consistent across an app.
Do
- Provide initials as a fallback for every avatar.
- Cap stacked groups with a +N count rather than showing dozens.
Don’t
- Don’t rely on the avatar image alone to identify a user.
- Don’t use colour-only badges to convey critical status.
Explore further
Ready to integrate?
Follow the Getting Started guide to install @codefast/ui, or browse the full component gallery.