HextaUI

Avatar

Baş harf yedekli kullanıcı fotoğrafları, durum rozetleri ve sayıya daralan yığılmış gruplar.

ALGH
ALATGH2 more
import {
  Avatar,
  AvatarBadge,
  AvatarFallback,
  AvatarGroup,
  AvatarImage,
} from "@/components/ui/avatar"

export function AvatarDemo() {
  return (
    <div className="flex flex-wrap items-center justify-center gap-8">
      <Avatar size="xl">
        <AvatarImage src="/preview/landscape.svg" alt="" />
        <AvatarFallback>AL</AvatarFallback>
        <AvatarBadge status="online" />
      </Avatar>
      <Avatar size="xl" shape="square">
        <AvatarFallback>GH</AvatarFallback>
      </Avatar>
      <AvatarGroup size="lg" max={4}>
        <Avatar>
          <AvatarImage src="/preview/landscape.svg" alt="" />
          <AvatarFallback>AL</AvatarFallback>
        </Avatar>
        <Avatar>
          <AvatarFallback>AT</AvatarFallback>
        </Avatar>
        <Avatar>
          <AvatarFallback>GH</AvatarFallback>
        </Avatar>
        <Avatar>
          <AvatarFallback>KJ</AvatarFallback>
        </Avatar>
        <Avatar>
          <AvatarFallback>LT</AvatarFallback>
        </Avatar>
      </AvatarGroup>
    </div>
  )
}
pnpm dlx shadcn@latest add https://hextaui.com/r/avatar.json

Bileşeni, HextaUI tema token'larını ve bileşenin bağımlı olduğu tüm HextaUI bileşenlerini ekler.

import {
  Avatar,
  AvatarBadge,
  AvatarFallback,
  AvatarGroup,
  AvatarImage,
} from "@/components/ui/avatar"
<Avatar>
  <AvatarImage src="/ada.jpg" alt="" />
  <AvatarFallback>AL</AvatarFallback>
</Avatar>
Avatar
├── AvatarImage
├── AvatarFallback
└── AvatarBadge

AvatarGroup
├── Avatar
└── AvatarGroupCount

Boyutlar ve şekiller

Daire veya kare olarak beş boyut. Baş harfler ve kullanıcı simgesi kutuyla birlikte ölçeklenir, kare köşeler boyutla birlikte küçülür. Boş bir <AvatarFallback /> kullanıcı simgesini gösterir.

import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"

const sizes = ["xs", "sm", "default", "lg", "xl"] as const
const shapes = ["circle", "square"] as const

export function AvatarSizes() {
  return (
    <div className="flex flex-col gap-4">
      {shapes.map((shape) => (
        <div key={shape} className="flex flex-wrap items-center gap-3">
          {sizes.map((size) => (
            <Avatar key={`photo-${size}`} size={size} shape={shape}>
              <AvatarImage src="/preview/landscape.svg" alt="" />
              <AvatarFallback>AL</AvatarFallback>
            </Avatar>
          ))}
          {sizes.map((size) => (
            <Avatar key={`initials-${size}`} size={size} shape={shape}>
              <AvatarFallback>LT</AvatarFallback>
            </Avatar>
          ))}
          {sizes.map((size) => (
            <Avatar key={`empty-${size}`} size={size} shape={shape}>
              <AvatarFallback />
            </Avatar>
          ))}
        </div>
      ))}
    </div>
  )
}

Yükleniyor

Fotoğraf yüklenirken baş harfler görünür, sonra fotoğraf üzerlerinde solarak belirir. Bozuk bir fotoğraf fallback'i korur. Hızlı fotoğraflarda baş harflerin göz kırpmaması için baş harfleri göstermeden önce beklemek üzere delay geçin.

"use client"

import * as React from "react"

import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { Button } from "@/components/ui/button"

export function AvatarLoading() {
  const [version, setVersion] = React.useState(0)
  const [loading, setLoading] = React.useState(false)
  const timer = React.useRef<number>(undefined)

  React.useEffect(() => () => window.clearTimeout(timer.current), [])

  const reload = () => {
    window.clearTimeout(timer.current)
    setLoading(true)
    timer.current = window.setTimeout(() => {
      setVersion((value) => value + 1)
      setLoading(false)
    }, 1200)
  }

  return (
    <div className="flex flex-wrap items-center gap-3">
      <Avatar size="xl">
        {loading ? null : (
          <AvatarImage src={`/preview/landscape.svg?v=${version}`} alt="" />
        )}
        <AvatarFallback>AT</AvatarFallback>
      </Avatar>
      <Avatar size="xl">
        <AvatarImage src="/preview/missing.png" alt="" />
        <AvatarFallback>BI</AvatarFallback>
      </Avatar>
      <Avatar size="xl">
        <AvatarImage src="/preview/landscape.svg" alt="" />
        <AvatarFallback delay={600}>GH</AvatarFallback>
      </Avatar>
      <Button variant="outline" size="sm" onClick={reload}>
        Load a new photo
      </Button>
    </div>
  )
}

Baş harfler

getInitials() ilk ve son baş harfi seçer. E-posta adreslerini, emojileri, CJK ve RTL adlarını, birleştirici işaretleri ve hiç harf içermeyen adları işler.

"use client"

import { Avatar, AvatarFallback, getInitials } from "@/components/ui/avatar"

const names = [
  "Ada Lovelace",
  "Madonna",
  "jean-luc picard",
  "[email protected]",
  "(Admin) John",
  "👩‍👩‍👧‍👦 Family",
  "山田 太郎",
  "محمد علي",
  "Z̷̢̛͖͓̰̈́algo T̵ext",
  "Mary Ann Evans Cross",
  "!!! ???",
  "",
]

export function AvatarInitials() {
  return (
    <ul className="grid w-full max-w-md grid-cols-1 gap-2 sm:grid-cols-2">
      {names.map((name) => (
        <li key={name} className="flex min-w-0 items-center gap-2 text-sm">
          <Avatar>
            <AvatarFallback>{getInitials(name)}</AvatarFallback>
          </Avatar>
          <span className="min-w-0 truncate text-muted-foreground">
            {name || "(empty)"}
          </span>
        </li>
      ))}
    </ul>
  )
}

Durum

<AvatarBadge /> her boyutta ve şekilde kenar üzerinde durur. Erişilebilir etiketli renkli bir nokta için status ayarlayın veya bir simge geçin. Durumu değiştirmek tek bir nabız oynatır.

"use client"

import * as React from "react"
import { IconCheck } from "@tabler/icons-react"

import {
  Avatar,
  AvatarBadge,
  AvatarFallback,
  AvatarImage,
  type AvatarStatus,
} from "@/components/ui/avatar"
import { Button } from "@/components/ui/button"

const sizes = ["xs", "sm", "default", "lg", "xl"] as const
const shapes = ["circle", "square"] as const
const statuses: AvatarStatus[] = ["online", "away", "busy", "offline"]

export function AvatarStatusDemo() {
  const [index, setIndex] = React.useState(0)
  const status = statuses[index]

  return (
    <div className="flex flex-col gap-4">
      {shapes.map((shape) => (
        <div key={shape} className="flex flex-wrap items-center gap-3">
          {sizes.map((size) => (
            <Avatar key={size} size={size} shape={shape}>
              <AvatarImage src="/preview/landscape.svg" alt="" />
              <AvatarFallback>GH</AvatarFallback>
              <AvatarBadge status={status} />
            </Avatar>
          ))}
          <Avatar size="lg" shape={shape}>
            <AvatarFallback>AT</AvatarFallback>
            <AvatarBadge>
              <IconCheck />
            </AvatarBadge>
          </Avatar>
        </div>
      ))}
      <div className="flex items-center gap-3">
        <Button
          variant="outline"
          size="sm"
          onClick={() => setIndex((index + 1) % statuses.length)}
        >
          Next status
        </Button>
        <span className="text-sm text-muted-foreground">{status}</span>
      </div>
    </div>
  )
}

Group

<AvatarGroup /> avatarlarını üst üste bindirir ve boyutunu ve şeklini ayarlar. max kalanları bir sayıya daraltır.

"use client"

import {
  Avatar,
  AvatarFallback,
  AvatarGroup,
  AvatarImage,
  getInitials,
} from "@/components/ui/avatar"

const people = [
  { name: "Ada Lovelace", image: "/preview/landscape.svg" },
  { name: "Alan Turing", image: "/preview/landscape.svg" },
  { name: "Grace Hopper", image: "/preview/landscape.svg" },
  { name: "Katherine Johnson", image: null },
  { name: "Linus Torvalds", image: null },
  { name: "Margaret Hamilton", image: null },
  { name: "Tim Berners-Lee", image: null },
  { name: "Barbara Liskov", image: null },
]

const sizes = ["xs", "sm", "default", "lg", "xl"] as const

export function AvatarGroupDemo() {
  return (
    <div className="flex flex-col items-start gap-4">
      {sizes.map((size) => (
        <AvatarGroup key={size} size={size} max={4}>
          {people.map((person) => (
            <Avatar key={person.name}>
              {person.image ? <AvatarImage src={person.image} alt="" /> : null}
              <AvatarFallback>{getInitials(person.name)}</AvatarFallback>
            </Avatar>
          ))}
        </AvatarGroup>
      ))}
      <AvatarGroup shape="square" max={5}>
        {people.map((person) => (
          <Avatar key={person.name}>
            {person.image ? <AvatarImage src={person.image} alt="" /> : null}
            <AvatarFallback>{getInitials(person.name)}</AvatarFallback>
          </Avatar>
        ))}
      </AvatarGroup>
    </div>
  )
}

Bağlantılı grup

render ile avatarları bağlantı olarak oluşturun ve her birine bir aria-label verin. Odaktaki avatar komşularının üstüne çıkar, böylece halka asla kesilmez. Toplam verinizden geliyorsa <AvatarGroupCount /> bileşenini kendiniz ekleyin.

"use client"

import {
  Avatar,
  AvatarFallback,
  AvatarGroup,
  AvatarGroupCount,
  getInitials,
} from "@/components/ui/avatar"

const team = [
  "Ada Lovelace",
  "Alan Turing",
  "Grace Hopper",
  "Linus Torvalds",
  "Margaret Hamilton",
]

export function AvatarLinkedGroup() {
  return (
    <AvatarGroup aria-label="Team" size="lg">
      {team.map((name) => (
        <Avatar key={name} render={<a href="#" aria-label={name} />}>
          <AvatarFallback>{getInitials(name)}</AvatarFallback>
        </Avatar>
      ))}
      <AvatarGroupCount count={3} />
    </AvatarGroup>
  )
}

Yerleşim

Avatarlar dar satırlarda asla küçülmez. size-20 gibi bir boyut sınıfı baş harfleri ve rozeti de ölçekler; uzun baş harfler asla taşmaz.

import {
  Avatar,
  AvatarBadge,
  AvatarFallback,
  AvatarImage,
} from "@/components/ui/avatar"

export function AvatarLayout() {
  return (
    <div className="flex flex-col items-start gap-4">
      <div className="flex w-64 max-w-full items-center gap-2 rounded-lg border p-2 text-sm">
        <Avatar>
          <AvatarImage src="/preview/landscape.svg" alt="" />
          <AvatarFallback>AL</AvatarFallback>
        </Avatar>
        <span className="min-w-0 truncate">
          Supercalifragilisticexpialidocious-team-workspace-name
        </span>
      </div>
      <div className="flex flex-wrap items-center gap-3">
        <Avatar className="size-20">
          <AvatarImage src="/preview/landscape.svg" alt="" />
          <AvatarFallback>KJ</AvatarFallback>
        </Avatar>
        <Avatar className="size-20" shape="square">
          <AvatarFallback>KJ</AvatarFallback>
          <AvatarBadge status="online" />
        </Avatar>
        <Avatar size="sm">
          <AvatarFallback>WWWWWWWW</AvatarFallback>
        </Avatar>
      </div>
    </div>
  )
}

Sağdan sola

Rozet son köşede kalır; RTL'de bu sol taraftır ve gruplar sağdan üst üste biner.

"use client"

import {
  Avatar,
  AvatarBadge,
  AvatarFallback,
  AvatarGroup,
  AvatarImage,
  getInitials,
} from "@/components/ui/avatar"

const people = [
  { name: "Ada Lovelace", image: "/preview/landscape.svg" },
  { name: "Alan Turing", image: "/preview/landscape.svg" },
  { name: "Grace Hopper", image: "/preview/landscape.svg" },
  { name: "Katherine Johnson", image: null },
  { name: "Linus Torvalds", image: null },
  { name: "Margaret Hamilton", image: null },
  { name: "Tim Berners-Lee", image: null },
  { name: "Barbara Liskov", image: null },
]

export function AvatarRtl() {
  return (
    <div dir="rtl" className="flex flex-wrap items-center gap-4">
      <Avatar size="lg">
        <AvatarFallback>{getInitials("محمد علي")}</AvatarFallback>
        <AvatarBadge status="online" />
      </Avatar>
      <AvatarGroup max={4}>
        {people.map((person) => (
          <Avatar key={person.name}>
            {person.image ? <AvatarImage src={person.image} alt="" /> : null}
            <AvatarFallback>{getInitials(person.name)}</AvatarFallback>
          </Avatar>
        ))}
      </AvatarGroup>
    </div>
  )
}

Avatarlar kendi başlarına odaklanılabilir değildir. Bağlantı veya düğme olarak oluşturulduklarında olağan tuşları alırlar.

TuşAction
TabOdağı sonraki bağlantılı avatara taşır.
EnterOdaktaki bağlantıyı izler.
  • Kişinin adı zaten avatarın yanındaysa alt="" kullanın; değilse alt metni olarak adını kullanın.
  • status içeren rozetler “Online”, “Away”, “Busy” veya “Offline” olarak duyurulur. Offline bir halka olarak çizilir; böylece durum asla yalnızca renge dayanmaz.
  • Gruplarda role="group" bulunur. Sayı “+3” değil, “3 more” olarak okunur.
  • Azaltılmış hareket açıkken fotoğraflar solmadan görünür ve durum değişiklikleri nabız atmaz.

Base UI avatar üzerine kuruludur. Her parça, oluşturduğu öğenin niteliklerini kabul eder. Stiller avatarVariants ve avatarBadgeVariants olarak dışa aktarılır.

PropTürVarsayılan
sizeBelirtilmezse gruptan devralınır.
"xs" | "sm" | "default" | "lg" | "xl""default"
shapeBelirtilmezse gruptan devralınır.
"circle" | "square""circle"
render
ReactElement | (props, state) => ReactElement<span>
ÖznitelikAçıklama
data-slot="avatar"CSS'te avatarları hedefleyin.
data-sizeÇözümlenen boyut.
data-shapeÇözümlenen şekil.
--avatar-radiusHer katmanın paylaştığı köşe yarıçapı.
PropTürVarsayılan
src
string–
alt
string–
onLoadingStatusChange
(status: "idle" | "loading" | "loaded" | "error") => void–
keepMountedGörseli önceden yüklemek yerine yerinde yükleyin; loading="lazy" veya next/image için.
booleanfalse
render
ReactElement | (props, state) => ReactElement<img>
ÖznitelikAçıklama
data-slot="avatar-image"CSS'te görselleri hedefleyin.
data-loadingGörsel yüklenirken bulunur.
data-errorGörsel yüklenemediğinde bulunur.
data-starting-styleGörsel solarak belirirken bulunur.
data-ending-styleGörsel solarak kaybolurken bulunur.
PropTürVarsayılan
childrenBoş veya yalnızca boşluk olduğunda kullanıcı simgesi gösterilir.
ReactNode<IconUser />
delayGöstermeden önce beklenecek milisaniye.
number0
render
ReactElement | (props, state) => ReactElement<span>
ÖznitelikAçıklama
data-slot="avatar-fallback"CSS'te fallback'leri hedefleyin.
data-readyGecikme geçene kadar false.
PropTürVarsayılan
statusNoktayı renklendirir ve yardımcı teknolojiler için etiketler. Bu olmadan rozet primary rengini kullanır.
"online" | "away" | "busy" | "offline"–
childrenRozetin içindeki bir simge. xs ve sm boyutlarında gizlenir.
ReactNode–
ÖznitelikAçıklama
data-slot="avatar-badge"CSS'te rozetleri hedefleyin.
data-statusGeçerli durum.
data-slot="avatar-badge-pulse"Durum değişikliğinden sonra oynatılan nabız.
PropTürVarsayılan
size
"xs" | "sm" | "default" | "lg" | "xl""default"
shape
"circle" | "square""circle"
maxSayı dahil kaç öğenin gösterileceği. 2'nin altındaki değerler 2'ye yükseltilir.
number–
ÖznitelikAçıklama
data-slot="avatar-group"CSS'te grupları hedefleyin.
data-sizeGrubun boyutu.
PropTürVarsayılan
count+3 olarak, 99'un üzerinde 99+ olarak gösterilir.
number–
childrenSayının yerine geçer, örneğin bir simgeyle.
ReactNode–
sizeBelirtilmezse gruptan devralınır.
"xs" | "sm" | "default" | "lg" | "xl"–
shapeBelirtilmezse gruptan devralınır.
"circle" | "square"–
ÖznitelikAçıklama
data-slot="avatar-group-count"CSS'te sayacı hedefleyin.
data-sizeÇözümlenen boyut.
data-shapeÇözümlenen şekil.

getInitials(name, max = 2) en fazla max büyük harfli baş harf döndürür: ilk kelimenin ve son kelimenin baş harfi. E-posta adresi için @ öncesindeki kısmı kullanır. Adda harf, sayı veya emoji yoksa boş dize döndürür; böylece fallback kullanıcı simgesini gösterir.

Kullanıldığı bloklar

Avatar üzerine kurulan bloklar.