Skip to content

Avatar

A user image with initials fallback for profile menus, comment threads, and team lists — with the neobrutalist thick-border treatment.

import {
  Avatar,
  AvatarBadge,

The avatar shows a user image and swaps in AvatarFallback — initials or an icon — while the image loads or when it fails, with no layout shift. Built on the Base UI Avatar component and styled to the neobrutalist recipe: a thick 2px border and bold heading-type initials.

Reach for it when:

  • Profile menus — the header avatar that opens account actions; see the Dropdown example.
  • Comment threads and activity feeds — a face next to every author line, with initials covering broken or missing photos.
  • Team and member lists — overlap collaborators with AvatarGroup and cap the overflow with AvatarGroupCount.

Installation

pnpm dlx shadcn@latest add https://neobrutalism.com/r/base/avatar.json
npx shadcn@latest add https://neobrutalism.com/r/base/avatar.json
yarn dlx shadcn@latest add https://neobrutalism.com/r/base/avatar.json
bunx --bun shadcn@latest add https://neobrutalism.com/r/base/avatar.json

Install the following dependencies:

pnpm add @base-ui/react
npm install @base-ui/react
yarn add @base-ui/react
bun add @base-ui/react

Copy and paste the following code into your project.

components/ui/avatar.tsx
"use client"

import * as React from "react"
import { Avatar as AvatarPrimitive } from "radix-ui"

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

function Avatar({
  className,
  size = "default",
  ...props
}: React.ComponentProps<typeof AvatarPrimitive.Root> & {
  size?: "default" | "sm" | "lg"
}) {
  return (
    <AvatarPrimitive.Root
      data-slot="avatar"
      data-size={size}
      className={cn(
        "group/avatar relative flex size-8 shrink-0 rounded-full border-2 select-none data-[size=lg]:size-10 data-[size=sm]:size-6",
        className
      )}
      {...props}
    />
  )
}

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

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

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-8 shrink-0 items-center justify-center rounded-full bg-muted text-sm text-muted-foreground ring-2 ring-background group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>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,
}

Update the import paths to match your project setup.

Usage

import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
<Avatar>
  <AvatarImage src="https://github.com/shadcn.png" />
  <AvatarFallback>CN</AvatarFallback>
</Avatar>

Composition

Use the following composition to build an Avatar:

Avatar
├── AvatarImage
├── AvatarFallback
└── AvatarBadge

Use the following composition to build an AvatarGroup:

AvatarGroup
├── Avatar
│   ├── AvatarImage
│   ├── AvatarFallback
│   └── AvatarBadge
├── Avatar
│   ├── AvatarImage
│   ├── AvatarFallback
│   └── AvatarBadge
└── AvatarGroupCount

Examples

Basic

A basic avatar component with an image and a fallback.

NB
import {
  Avatar,
  AvatarFallback,

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,

Use the className prop to add custom styles to the badge such as custom colors, sizes, etc.

<Avatar>
  <AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
  <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 { PlusIcon } from "lucide-react"

import {

Avatar Group

Use the AvatarGroup component to add a group of avatars.

import {
  Avatar,
  AvatarFallback,

Avatar Group Count

Use <AvatarGroupCount> to add a count to the group.

import {
  Avatar,
  AvatarFallback,

Avatar Group with Icon

You can also use an icon inside <AvatarGroupCount>.

import { PlusIcon } from "lucide-react"

import {

Sizes

Use the size prop to change the size of the avatar.

import {
  Avatar,
  AvatarFallback,

You can use the Avatar component as a trigger for a dropdown menu.

"use client"

import {

RTL

To enable RTL support in Neobrutalism.com, see the RTL configuration guide.

"use client"

import * as React from "react"

Accessibility

An avatar is an image, so image rules apply: give AvatarImage an alt naming the person when the avatar is the only thing identifying them, and alt="" when a visible name sits right next to it — otherwise screen readers announce the name twice. AvatarFallback initials are plain text and get read aloud, so keep them meaningful. When the avatar opens a menu (see Dropdown), put the accessible name on the trigger button, not the image.

API Reference

Avatar

The Avatar component is the root component that wraps the avatar image and fallback.

PropTypeDefault
size"default" | "sm" | "lg""default"
classNamestring-

AvatarImage

The AvatarImage component displays the avatar image. It accepts all Base UI Avatar Image props.

PropTypeDefault
srcstring-
altstring-
classNamestring-

AvatarFallback

The AvatarFallback component displays a fallback when the image fails to load. It accepts all Base UI Avatar Fallback props.

PropTypeDefault
classNamestring-

AvatarBadge

The AvatarBadge component displays a badge indicator on the avatar, typically positioned at the bottom right.

PropTypeDefault
classNamestring-

AvatarGroup

The AvatarGroup component displays a group of avatars with overlapping styling.

PropTypeDefault
classNamestring-

AvatarGroupCount

The AvatarGroupCount component displays a count indicator in an avatar group, typically showing the number of additional avatars.

PropTypeDefault
classNamestring-

For more information about Base UI Avatar props, see the Base UI documentation.