Zum Inhalt springen

Avatar

Ein Benutzerbild mit Initialen als Ausweichlösung für Profilmenüs, Kommentarthreads und Teamlisten – im neobrutalistischen Stil mit dickem Rahmen.

import {
  Avatar,
  AvatarBadge,

Der Avatar zeigt ein Profilbild und blendet AvatarFallback ein – Initialen oder ein Icon –, während das Bild lädt oder wenn es nicht geladen werden kann, ganz ohne Layoutverschiebung. Er basiert auf der Base UI Avatar-Komponente und folgt dem neobrutalistischen Rezept: ein dicker 2-px-Rahmen und kräftige Initialen in der Überschriftenschrift.

Die richtige Wahl für:

  • Profilmenüs – der Avatar im Header, der die Kontoaktionen öffnet; siehe das Dropdown-Beispiel.
  • Kommentar-Threads und Aktivitäts-Feeds – ein Gesicht neben jeder Autorenzeile, mit Initialen als Ersatz für kaputte oder fehlende Fotos.
  • Team- und Mitgliederlisten – überlappe Teammitglieder mit AvatarGroup und begrenze den Überlauf mit 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

Installiere die folgenden Abhängigkeiten:

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

Kopiere den folgenden Code und füge ihn in dein Projekt ein.

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,
}

Passe die Import-Pfade an die Struktur deines Projekts an.

Verwendung

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

Komposition

Verwende die folgende Komposition, um einen Avatar aufzubauen:

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

Verwende die folgende Komposition, um eine AvatarGroup aufzubauen:

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

Beispiele

Basis

Eine einfache Avatar-Komponente mit einem Bild und einem Fallback.

NB
import {
  Avatar,
  AvatarFallback,

Badge

Verwende die Komponente AvatarBadge, um dem Avatar ein Badge hinzuzufügen. Das Badge wird unten rechts am Avatar positioniert.

import {
  Avatar,
  AvatarBadge,

Verwende die Prop className, um dem Badge benutzerdefinierte Stile wie Farben, Größen usw. hinzuzufügen.

<Avatar>
  <AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
  <AvatarFallback>CN</AvatarFallback>
  <AvatarBadge className="bg-green-600 dark:bg-green-800" />
</Avatar>

Badge mit Icon

Du kannst auch ein Icon innerhalb von <AvatarBadge> verwenden.

import { PlusIcon } from "lucide-react"

import {

Avatar-Gruppe

Verwende die Komponente AvatarGroup, um eine Gruppe von Avataren hinzuzufügen.

import {
  Avatar,
  AvatarFallback,

Avatar-Gruppenzähler

Verwende <AvatarGroupCount>, um der Gruppe einen Zähler hinzuzufügen.

import {
  Avatar,
  AvatarFallback,

Avatar-Gruppe mit Icon

Du kannst auch ein Icon innerhalb von <AvatarGroupCount> verwenden.

import { PlusIcon } from "lucide-react"

import {

Größen

Verwende die Prop size, um die Größe des Avatars zu ändern.

import {
  Avatar,
  AvatarFallback,

Du kannst die Avatar-Komponente als Trigger für ein Dropdown-Menü verwenden.

"use client"

import {

RTL

Um die RTL-Unterstützung in Neobrutalism zu aktivieren, siehe die RTL-Konfigurationsanleitung.

"use client"

import * as React from "react"

Barrierefreiheit

Ein Avatar ist ein Bild, also gelten Bildregeln: Gib AvatarImage ein alt, das die Person benennt, wenn der Avatar das Einzige ist, was sie identifiziert – und alt="", wenn direkt daneben ein sichtbarer Name steht, sonst kündigen Screenreader den Namen doppelt an. Die Initialen in AvatarFallback sind gewöhnlicher Text und werden vorgelesen, halte sie also aussagekräftig. Öffnet der Avatar ein Menü (siehe Dropdown), gehört der zugängliche Name auf den Trigger-Button, nicht auf das Bild.

API-Referenz

Avatar

Die Avatar-Komponente ist die Wurzelkomponente, die Avatar-Bild und Fallback umschließt.

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

AvatarImage

Die AvatarImage-Komponente zeigt das Avatar-Bild. Sie akzeptiert alle Props von Base UI Avatar Image.

PropTypeDefault
srcstring-
altstring-
classNamestring-

AvatarFallback

Die AvatarFallback-Komponente zeigt einen Fallback, wenn das Bild nicht geladen werden kann. Sie akzeptiert alle Props von Base UI Avatar Fallback.

PropTypeDefault
classNamestring-

AvatarBadge

Die AvatarBadge-Komponente zeigt einen Badge-Indikator auf dem Avatar, üblicherweise unten rechts positioniert.

PropTypeDefault
classNamestring-

AvatarGroup

Die AvatarGroup-Komponente zeigt eine Gruppe von Avataren mit überlappender Darstellung.

PropTypeDefault
classNamestring-

AvatarGroupCount

Die AvatarGroupCount-Komponente zeigt einen Zähler-Indikator in einer Avatar-Gruppe, üblicherweise die Anzahl der zusätzlichen Avatare.

PropTypeDefault
classNamestring-

Weitere Informationen zu den Props von Base UI Avatar findest du in der Base-UI-Dokumentation.