Free shadcn/ui avatar component for React — a Radix image with a graceful initials fallback. Sizes, an avatar group/stack, status indicators, and square/ringed shapes. The examples official shadcn never shipped.

Installation

1 Configure registry — once per project
{
  "registries": {
    "@designrevision": "https://registry.designrevision.com/r/{name}.json"
  }
}

Add to your existing components.json. Requires shadcn/ui v2.3+.

2 Install the component

Packages

@radix-ui/react-avatar
utils

Props

No props documented yet.

Copied!
components/ui/avatar.tsx
"use client"

import * as React from "react"
import * as AvatarPrimitive from "@radix-ui/react-avatar"

import { cn } from "@/lib/utils"

function Avatar({
  className,
  ...props
}: React.ComponentProps<typeof AvatarPrimitive.Root>) {
  return (
    <AvatarPrimitive.Root
      data-slot="avatar"
      className={cn(
        "relative flex size-8 shrink-0 overflow-hidden rounded-full",
        className
      )}
      {...props}
    />
  )
}

function AvatarImage({
  className,
  ...props
}: React.ComponentProps<typeof AvatarPrimitive.Image>) {
  return (
    <AvatarPrimitive.Image
      data-slot="avatar-image"
      className={cn("aspect-square size-full", className)}
      {...props}
    />
  )
}

function AvatarFallback({
  className,
  ...props
}: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
  return (
    <AvatarPrimitive.Fallback
      data-slot="avatar-fallback"
      className={cn(
        "bg-muted flex size-full items-center justify-center rounded-full",
        className
      )}
      {...props}
    />
  )
}

export { Avatar, AvatarImage, AvatarFallback }

Examples

Avatar

The canonical avatar — an image with an initials fallback that shows while it loads or if it fails.

Packages

avatar

Props

No props documented yet.

Copied!
components/ui/avatar-demo-01.tsx
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"

export default function AvatarDemo01() {
  return (
    <Avatar>
      <AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
      <AvatarFallback>CN</AvatarFallback>
    </Avatar>
  )
}

Fallbacks

Initials fallbacks for when there is no image — plain and colored.

Packages

avatar

Props

No props documented yet.

Copied!
components/ui/avatar-fallback-01.tsx
import { Avatar, AvatarFallback } from "@/components/ui/avatar"

const colored = [
  { initials: "AL", color: "bg-rose-500" },
  { initials: "BC", color: "bg-blue-500" },
  { initials: "CD", color: "bg-emerald-500" },
  { initials: "DE", color: "bg-violet-500" },
]

export default function AvatarFallbackDemo01() {
  return (
    <div className="flex items-center gap-3">
      {/* Plain fallback (shows when there's no image). */}
      <Avatar>
        <AvatarFallback>JD</AvatarFallback>
      </Avatar>
      {/* Colored fallbacks. */}
      {colored.map((person) => (
        <Avatar key={person.initials}>
          <AvatarFallback className={`${person.color} text-white`}>
            {person.initials}
          </AvatarFallback>
        </Avatar>
      ))}
    </div>
  )
}

Sizes

Avatars from `size-6` to `size-16` — set the size with a className on `Avatar`.

Packages

avatar

Props

No props documented yet.

Copied!
components/ui/avatar-sizes-01.tsx
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"

const sizes = ["size-6", "size-8", "size-10", "size-12", "size-16"]

export default function AvatarSizes01() {
  return (
    <div className="flex items-center gap-4">
      {sizes.map((size) => (
        <Avatar key={size} className={size}>
          <AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
          <AvatarFallback>CN</AvatarFallback>
        </Avatar>
      ))}
    </div>
  )
}

Avatar group

A stacked group of overlapping avatars (`-space-x` + ring) with a "+N" overflow.

Packages

avatar

Props

No props documented yet.

Copied!
components/ui/avatar-group-01.tsx
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"

const members = [
  { src: "https://github.com/shadcn.png", fallback: "CN" },
  { src: "https://github.com/leerob.png", fallback: "LR" },
  { src: "https://github.com/evilrabbit.png", fallback: "ER" },
  { src: "https://github.com/vercel.png", fallback: "VC" },
]

export default function AvatarGroup01() {
  return (
    <div className="flex -space-x-2">
      {members.map((member, index) => (
        <Avatar key={index} className="ring-background ring-2">
          <AvatarImage src={member.src} alt="" />
          <AvatarFallback>{member.fallback}</AvatarFallback>
        </Avatar>
      ))}
      <Avatar className="ring-background ring-2">
        <AvatarFallback className="text-muted-foreground text-xs">
          +3
        </AvatarFallback>
      </Avatar>
    </div>
  )
}

Status indicator

An online / away / offline status dot pinned to the bottom-right of the avatar.

Packages

avatar

Props

No props documented yet.

Copied!
components/ui/avatar-status-01.tsx
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"

const people = [
  { src: "https://github.com/shadcn.png", fallback: "CN", status: "bg-green-500", label: "Online" },
  { src: "https://github.com/leerob.png", fallback: "LR", status: "bg-amber-500", label: "Away" },
  { src: "https://github.com/evilrabbit.png", fallback: "ER", status: "bg-muted-foreground", label: "Offline" },
]

export default function AvatarStatus01() {
  return (
    <div className="flex items-center gap-6">
      {people.map((person, index) => (
        <div key={index} className="relative">
          <Avatar className="size-10">
            <AvatarImage src={person.src} alt="" />
            <AvatarFallback>{person.fallback}</AvatarFallback>
          </Avatar>
          <span
            title={person.label}
            className={`ring-background absolute right-0 bottom-0 size-3 rounded-full ring-2 ${person.status}`}
          />
        </div>
      ))}
    </div>
  )
}

Shape & ring

Round (default), square (`rounded-lg`), and a ringed avatar with `ring-offset`.

Packages

avatar

Props

No props documented yet.

Copied!
components/ui/avatar-shapes-01.tsx
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"

export default function AvatarShapes01() {
  return (
    <div className="flex items-center gap-6">
      {/* Default round */}
      <Avatar className="size-12">
        <AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
        <AvatarFallback>CN</AvatarFallback>
      </Avatar>
      {/* Square (rounded-lg) */}
      <Avatar className="size-12 rounded-lg">
        <AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
        <AvatarFallback className="rounded-lg">CN</AvatarFallback>
      </Avatar>
      {/* With a ring */}
      <Avatar className="ring-primary ring-offset-background size-12 ring-2 ring-offset-2">
        <AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
        <AvatarFallback>CN</AvatarFallback>
      </Avatar>
    </div>
  )
}

With name

The user-row pattern — an avatar beside a name and email, the second falling back to initials.

Packages

avatar

Props

No props documented yet.

Copied!
components/ui/avatar-detail-01.tsx
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"

const people = [
  { src: "https://github.com/shadcn.png", name: "shadcn", email: "[email protected]", fallback: "CN" },
  { src: "", name: "Ada Lovelace", email: "[email protected]", fallback: "AL" },
]

export default function AvatarDetail01() {
  return (
    <div className="grid gap-4">
      {people.map((person, index) => (
        <div key={index} className="flex items-center gap-3">
          <Avatar>
            <AvatarImage src={person.src} alt={person.name} />
            <AvatarFallback>{person.fallback}</AvatarFallback>
          </Avatar>
          <div className="grid gap-0.5">
            <p className="text-sm leading-none font-medium">{person.name}</p>
            <p className="text-muted-foreground text-xs">{person.email}</p>
          </div>
        </div>
      ))}
    </div>
  )
}

Frequently asked questions

Yes — it is the canonical shadcn/ui avatar, built on Radix Avatar with three parts (Avatar, AvatarImage, AvatarFallback). Official ships one demo; we add colored fallbacks, sizes, an avatar group, status indicators, square/ringed shapes, and the avatar-with-name row.
AvatarImage only renders once the image has actually loaded. Until then — and if the image errors or there is no src — AvatarFallback is shown instead. Put initials (or an icon) in the fallback. Radix can delay the fallback slightly (delayMs) to avoid a flash when the image loads quickly.
Render an AvatarFallback with the initials and either no AvatarImage or one whose src is empty/missing. The fallback fills the avatar; give it a background and text color (e.g. bg-rose-500 text-white) for colored initials. The Fallbacks example shows both.
Put the avatars in a flex container with a negative gap (-space-x-2) so they overlap, and give each a ring matching the background (ring-2 ring-background) so they read as separate. Add a final avatar with a "+N" fallback for overflow. The Avatar group example is the pattern.
Wrap the Avatar in a relative container and add an absolutely-positioned span at bottom-0 right-0 — a small rounded-full dot with a ring (ring-2 ring-background) and a color for the state (green = online, amber = away, muted = offline). The Status indicator example shows all three; give the dot a title or sr-only label so it is not color-only.
Size it with a className on Avatar — the default is size-8; use size-10, size-12, etc. For a square avatar, set rounded-lg on the Avatar (and the AvatarFallback) to override the default rounded-full. Add ring-2 ring-offset-2 for a ringed look. The Sizes and Shape & ring examples cover both.
Give AvatarImage a meaningful alt (the person's name) — or alt="" if the name is already shown beside it, so screen readers do not announce it twice. Initials in a fallback are decorative; the surrounding name is what matters. Never convey status by the dot color alone — pair it with a label.