Use Avatar to represent a person or entity in a compact space. Keep a fallback for slow or failed image requests. It does not identify a user, load account data, or implement an account menu.
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
export default function AvatarDemo() {
return (
<Avatar>
<AvatarImage src="/avatar-placeholder.svg" alt="John Doe" />
<AvatarFallback>JD</AvatarFallback>
</Avatar>
);
}
#Installation
Complete the base setup. For manual installation:
First time? Install the shared base once.
npx shadcn@latest add https://neobrutal-ui.andongmin.com/r/avatar.jsonnpm install @base-ui/react@^1.9.0Create components/ui/avatar.tsx:
"use client";
import { Avatar as AvatarPrimitive } from "@base-ui/react/avatar";
import type * as React from "react";
import { cn } from "@/lib/utils";
function Avatar({
className,
size = "default",
...props
}: AvatarPrimitive.Root.Props & {
size?: "default" | "sm" | "lg";
}) {
return (
<AvatarPrimitive.Root
data-slot="avatar"
data-size={size}
{...props}
className={(state) =>
cn(
"group/avatar relative flex size-10 shrink-0 overflow-hidden rounded-full outline-2 outline-border select-none data-[size=lg]:size-12 data-[size=sm]:size-8",
typeof className === "function" ? className(state) : className,
)
}
/>
);
}
function AvatarImage({ className, ...props }: AvatarPrimitive.Image.Props) {
return (
<AvatarPrimitive.Image
data-slot="avatar-image"
{...props}
className={(state) =>
cn(
"aspect-square size-full rounded-full object-cover",
typeof className === "function" ? className(state) : className,
)
}
/>
);
}
function AvatarFallback({ className, ...props }: AvatarPrimitive.Fallback.Props) {
return (
<AvatarPrimitive.Fallback
data-slot="avatar-fallback"
{...props}
className={(state) =>
cn(
"flex size-full items-center justify-center rounded-full bg-secondary-background text-sm font-base text-foreground group-data-[size=sm]/avatar:text-xs",
typeof className === "function" ? className(state) : className,
)
}
/>
);
}
function AvatarBadge({ className, ...props }: React.ComponentProps<"span">) {
return (
<span
data-slot="avatar-badge"
className={cn(
"absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground bg-blend-color ring-2 ring-background select-none",
"group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden",
"group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2",
"group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2",
className,
)}
{...props}
/>
);
}
function AvatarGroup({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="avatar-group"
className={cn(
"group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background",
className,
)}
{...props}
/>
);
}
function AvatarGroupCount({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="avatar-group-count"
className={cn(
"relative flex size-10 shrink-0 items-center justify-center rounded-full bg-secondary-background text-sm font-base text-foreground ring-2 ring-border group-has-data-[size=lg]/avatar-group:size-12 group-has-data-[size=sm]/avatar-group:size-8 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3",
className,
)}
{...props}
/>
);
}
export { Avatar, AvatarImage, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarBadge };
#Usage
import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
export default function MemberAvatar() {
return (
<div className="flex items-center gap-3">
<Avatar>
<AvatarImage src="/images/member.jpg" alt="" />
<AvatarFallback aria-hidden="true">JD</AvatarFallback>
</Avatar>
<span>Jordan Davis</span>
</div>
);
}Add your own image asset. This example keeps the name visible, so the image is decorative. An avatar used alone needs an accessible name for the person or action it represents.
#API reference
| Prop / part | Purpose | Default |
|---|---|---|
Avatar.size | sm, default, or lg | default |
AvatarImage.src / alt | Image address and alternative text | — |
AvatarFallback | Initials or non-image content | — |
AvatarFallback.delay | Fallback delay in milliseconds | Primitive default |
AvatarBadge | Status marker | — |
AvatarGroup / AvatarGroupCount | Group and remaining count | — |
#Accessibility
Avoid announcing the same name twice when it is already adjacent to the image. A status badge needs text or an accessible label; color alone is insufficient. Put an interactive avatar inside a real button or link with an explicit name, rather than adding click handling to a generic container.
#Examples
#Fallback
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
export default function AvatarFallbackDemo() {
return (
<Avatar>
<AvatarFallback>CN</AvatarFallback>
</Avatar>
);
}