Avatar
A compact visual identity for a person or an organization, with an image, initials fallback and optional presence status.
import {
Avatar,
AvatarFallback,
AvatarGroup,
AvatarGroupCount,
AvatarImage,
} from "@/components/ui/avatar"
import aurora from "./assets/aurora.svg"
import ember from "./assets/ember.svg"
import tide from "./assets/tide.svg"
export default function AvatarDemo() {
return (
<AvatarGroup>
<Avatar size="lg">
<AvatarImage src={aurora.src} alt="Maya Chen" />
<AvatarFallback>MC</AvatarFallback>
</Avatar>
<Avatar size="lg">
<AvatarImage src={ember.src} alt="Jonah Okafor" />
<AvatarFallback>JO</AvatarFallback>
</Avatar>
<Avatar size="lg">
<AvatarImage src={tide.src} alt="Lena Park" />
<AvatarFallback>LP</AvatarFallback>
</Avatar>
<Avatar size="lg">
<AvatarFallback>RS</AvatarFallback>
</Avatar>
<AvatarGroupCount>+8</AvatarGroupCount>
</AvatarGroup>
)
}Anatomy
- 1RootA circle for people, a rounded square for organizations. Five sizes, from 20 to 56px.
- 2BadgeAn optional status dot, ringed in the page color so it separates from the image.
- 3FallbackInitials on a neutral fill, shown while the image loads — or instead of it, when there is none.
- 4GroupOverlapping avatars, each ringed in the page color.
- 5CountHow many more people there are, sized to match the group.
Installation
$ pnpm dlx shadcn@latest add https://www.prfct.dev/r/avatar.jsonUsage
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"<Avatar>
<AvatarImage src="/avatars/maya.png" alt="Maya Chen" />
<AvatarFallback>MC</AvatarFallback>
</Avatar>Always include an AvatarFallback. It renders while the image loads and permanently when the image is missing or fails, so a slow network or a deleted file never leaves a hole in the layout.
Examples
Sizes
Five sizes follow the control scale: xs 20, sm 24, default 32, lg 40 and xl 56 pixels. Initials scale with the avatar so they stay optically centered.
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import aurora from "./assets/aurora.svg"
const sizes = ["xs", "sm", "default", "lg", "xl"] as const
export default function AvatarSizes() {
return (
<div className="flex flex-col items-center gap-6">
<div className="flex items-end gap-4">
{sizes.map((size) => (
<Avatar key={size} size={size}>
<AvatarImage src={aurora.src} alt="Maya Chen" />
<AvatarFallback>MC</AvatarFallback>
</Avatar>
))}
</div>
<div className="flex items-end gap-4">
{sizes.map((size) => (
<Avatar key={size} size={size}>
<AvatarFallback>MC</AvatarFallback>
</Avatar>
))}
</div>
</div>
)
}Fallback
When there is no image, show two uppercase initials — given name and family name. For people you know nothing about, use a neutral icon and give it an accessible name.
import { UserIcon } from "lucide-react"
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import dusk from "./assets/dusk.svg"
export default function AvatarFallbackExample() {
return (
<div className="flex items-center gap-6">
<div className="flex flex-col items-center gap-2">
<Avatar size="lg">
<AvatarImage src={dusk.src} alt="Priya Raman" />
<AvatarFallback>PR</AvatarFallback>
</Avatar>
<span className="text-xs text-muted-foreground">Image</span>
</div>
<div className="flex flex-col items-center gap-2">
<Avatar size="lg">
<AvatarFallback>PR</AvatarFallback>
</Avatar>
<span className="text-xs text-muted-foreground">Initials</span>
</div>
<div className="flex flex-col items-center gap-2">
<Avatar size="lg">
<AvatarFallback>
<UserIcon className="size-4" aria-hidden="true" />
<span className="sr-only">Unknown user</span>
</AvatarFallback>
</Avatar>
<span className="text-xs text-muted-foreground">Anonymous</span>
</div>
</div>
)
}delay={600} to AvatarFallback to show it only when loading is genuinely slow.Shape
Circles are for people; rounded squares are for things people belong to — workspaces, organizations, apps. The shape carries meaning, so keep it consistent across the product.
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import aurora from "./assets/aurora.svg"
import moss from "./assets/moss.svg"
export default function AvatarShape() {
return (
<div className="grid justify-items-start gap-6 sm:grid-flow-col sm:gap-10">
<div className="flex items-center gap-3">
<Avatar size="lg">
<AvatarImage src={aurora.src} alt="Maya Chen" />
<AvatarFallback>MC</AvatarFallback>
</Avatar>
<div className="flex flex-col whitespace-nowrap">
<span className="text-sm font-medium">Maya Chen</span>
<span className="text-xs text-muted-foreground">Person · circle</span>
</div>
</div>
<div className="flex items-center gap-3">
<Avatar size="lg" shape="square">
<AvatarImage src={moss.src} alt="Northwind" />
<AvatarFallback>NW</AvatarFallback>
</Avatar>
<div className="flex flex-col whitespace-nowrap">
<span className="text-sm font-medium">Northwind</span>
<span className="text-xs text-muted-foreground">
Workspace · square
</span>
</div>
</div>
</div>
)
}Status
AvatarBadge sits on the bottom-right edge with a ring in the page color, so it reads on any background. It defaults to the success color for online; recolor it with a semantic token for other states, and always include a text label for screen readers.
import { CheckIcon } from "lucide-react"
import {
Avatar,
AvatarBadge,
AvatarFallback,
AvatarImage,
} from "@/components/ui/avatar"
import aurora from "./assets/aurora.svg"
import ember from "./assets/ember.svg"
import tide from "./assets/tide.svg"
export default function AvatarWithBadge() {
return (
<div className="flex items-center gap-8">
<Avatar size="lg">
<AvatarImage src={aurora.src} alt="Maya Chen" />
<AvatarFallback>MC</AvatarFallback>
<AvatarBadge>
<span className="sr-only">Online</span>
</AvatarBadge>
</Avatar>
<Avatar size="lg">
<AvatarImage src={ember.src} alt="Jonah Okafor" />
<AvatarFallback>JO</AvatarFallback>
<AvatarBadge className="bg-warning-9">
<span className="sr-only">Away</span>
</AvatarBadge>
</Avatar>
<Avatar size="lg">
<AvatarImage src={tide.src} alt="Lena Park" />
<AvatarFallback>LP</AvatarFallback>
<AvatarBadge className="bg-gray-9">
<span className="sr-only">Offline</span>
</AvatarBadge>
</Avatar>
<Avatar size="xl">
<AvatarFallback>RS</AvatarFallback>
<AvatarBadge className="bg-brand text-brand-foreground">
<CheckIcon aria-hidden="true" />
<span className="sr-only">Verified</span>
</AvatarBadge>
</Avatar>
</div>
)
}Group
Stack avatars to show who is involved without listing everyone. Show three to five, then summarize the rest with AvatarGroupCount. Each avatar gets a ring in the page color so overlaps stay crisp.
import {
Avatar,
AvatarFallback,
AvatarGroup,
AvatarGroupCount,
AvatarImage,
} from "@/components/ui/avatar"
import aurora from "./assets/aurora.svg"
import dusk from "./assets/dusk.svg"
import ember from "./assets/ember.svg"
import tide from "./assets/tide.svg"
const people = [
{ name: "Maya Chen", initials: "MC", image: aurora.src },
{ name: "Jonah Okafor", initials: "JO", image: ember.src },
{ name: "Lena Park", initials: "LP", image: tide.src },
{ name: "Priya Raman", initials: "PR", image: dusk.src },
]
export default function AvatarGroupExample() {
return (
<div className="flex flex-col items-center gap-6">
{(["sm", "default", "lg"] as const).map((size) => (
<AvatarGroup
key={size}
aria-label="Project members: Maya Chen, Jonah Okafor, Lena Park, Priya Raman and 12 others"
>
{people.map((person) => (
<Avatar key={person.name} size={size}>
<AvatarImage src={person.image} alt={person.name} />
<AvatarFallback>{person.initials}</AvatarFallback>
</Avatar>
))}
<AvatarGroupCount>+12</AvatarGroupCount>
</AvatarGroup>
))}
</div>
)
}With text
Most of the time an avatar sits next to a name. Because the name is already visible, the avatar is decorative: give the image an empty alt so assistive technology doesn't announce the name twice.
import {
Avatar,
AvatarBadge,
AvatarFallback,
AvatarImage,
} from "@/components/ui/avatar"
import { Badge } from "@/components/ui/badge"
import aurora from "./assets/aurora.svg"
export default function AvatarWithText() {
return (
<div className="flex w-full max-w-sm items-center gap-3 rounded-xl border bg-card p-4 shadow-raised">
<Avatar size="lg">
<AvatarImage src={aurora.src} alt="" />
<AvatarFallback>MC</AvatarFallback>
<AvatarBadge>
<span className="sr-only">Online</span>
</AvatarBadge>
</Avatar>
<div className="flex min-w-0 flex-1 flex-col">
<span className="truncate text-sm font-medium">Maya Chen</span>
<span className="truncate text-body-xs text-muted-foreground">
maya@northwind.dev
</span>
</div>
<Badge variant="secondary">Owner</Badge>
</div>
)
}Guidelines
When to use
- To help people recognize who did something: comment authors, assignees, collaborators, account owners.
- To identify a workspace, organization or connected app in switchers and lists.
When not to use
- For decorative or editorial imagery — use a regular image.
- For objects that aren't people or organizations, such as files or integrations in a list — use Item with an icon.
- As the only way to identify someone in a dense table. Pair it with a name, or make the name available in a tooltip.
Consistent identity
Initials
Images
- Use a square source at least twice the rendered size (112px for
xl) so avatars stay sharp on high-density screens. - Crop around the face or logo; the avatar applies
object-coverand clips to its shape. - Don't add borders — every avatar already has a hairline inner ring that keeps light images from dissolving into light surfaces.
Accessibility
- Name the image.
AvatarImagerenders an<img>: setaltto the person's or organization's name. When the name is visible next to the avatar, setalt=""and addaria-hiddento theAvatarso the initials aren't announced as letters. - Status needs words. The badge is color and position only. Put a visually hidden label inside it (
<span className="sr-only">Online</span>), and show presence as text wherever it matters. - Groups need a summary.
AvatarGroupis agroup, so a label on it is announced. Give it anaria-labelthat lists the people or states how many there are — "Project members: Maya Chen, Jonah Okafor and 12 others". - Contrast. Fallback initials (
gray-11ongray-3) meet 4.5:1 in both modes.
API reference
Avatar
The root. Accepts every prop of the Base UI Avatar Root.
AvatarImage
AvatarFallback
AvatarBadge
A <span> positioned on the avatar's edge. Defaults to the success color; override with a background token such as bg-warning-9. Icons inside are sized for you from default up and hidden at xs and sm, where the dot is too small to hold one.
AvatarGroup
A <div> with role="group" that overlaps its avatars and rings them in the page color. Accepts all div props, including aria-label.
AvatarGroupCount
A <div> for the "+N" summary at the end of a group. It follows the size of the avatars in the group automatically.