跳到内容

头像

用于个人资料菜单、评论线程和团队列表的用户头像,采用首字母备选方案,并应用了新粗野主义风格的粗边框处理。

import {
  Avatar,
  AvatarBadge,

头像展示用户图片,并在图片加载中或加载失败时换上 AvatarFallback——首字母缩写或一个图标——整个过程不产生布局跳动。它基于 Base UI Avatar 组件构建,并按新粗野主义的配方设计:2px 的粗边框,以及标题字体的加粗首字母。

适合以下场景:

  • 个人资料菜单——顶栏里那个点开账户操作的头像,参见下拉菜单示例。
  • 评论区与动态流——每一行作者信息旁都有一张脸,图片损坏或缺失时由首字母兜住。
  • 团队与成员列表——用 AvatarGroup 让协作者相互叠压,再用 AvatarGroupCount 收住多出来的部分。

安装

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

安装以下依赖项:

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

将以下代码复制并粘贴到您的项目中。

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

更新导入路径以匹配您的项目设置。

用法

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

组合

使用以下组合来构建 Avatar

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

使用以下组合来构建 AvatarGroup

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

示例

基础

一个带有图片和后备内容的基础头像组件。

NB
import {
  Avatar,
  AvatarFallback,

徽章

使用 AvatarBadge 组件向头像添加徽章。徽章位于头像的右下角。

import {
  Avatar,
  AvatarBadge,

使用 className 属性可以为徽章添加自定义样式,例如自定义颜色、尺寸等。

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

带图标的徽章

您也可以在 <AvatarBadge> 内使用图标。

import { PlusIcon } from "lucide-react"

import {

头像组

使用 AvatarGroup 组件添加一组头像。

import {
  Avatar,
  AvatarFallback,

头像组计数

使用 <AvatarGroupCount> 向头像组添加计数。

import {
  Avatar,
  AvatarFallback,

带图标的头像组

您也可以在 <AvatarGroupCount> 内使用图标。

import { PlusIcon } from "lucide-react"

import {

尺寸

使用 size 属性来改变头像的尺寸。

import {
  Avatar,
  AvatarFallback,

下拉菜单

您可以将 Avatar 组件用作下拉菜单的触发器。

"use client"

import {

RTL

要在 Neobrutalism 中启用 RTL 支持,请参阅 RTL 配置指南

"use client"

import * as React from "react"

无障碍

头像本质上是图片,所以图片的规则同样适用:当头像是唯一能标识某人的东西时,给 AvatarImage 写上写明姓名的 alt;当旁边已经有可见的姓名时,用 alt=""——否则屏幕阅读器会把名字念两遍。AvatarFallback 里的首字母是纯文本,会被朗读出来,所以要让它保持有意义。当头像用来打开菜单时(参见下拉菜单),请把无障碍名称放在触发按钮上,而不是图片上。

API 参考

Avatar

Avatar 组件是包裹头像图片和后备内容的根组件。

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

AvatarImage

AvatarImage 组件显示头像图片。它接受所有 Base UI Avatar Image 属性。

PropTypeDefault
srcstring-
altstring-
classNamestring-

AvatarFallback

AvatarFallback 组件在图片加载失败时显示后备内容。它接受所有 Base UI Avatar Fallback 属性。

PropTypeDefault
classNamestring-

AvatarBadge

AvatarBadge 组件在头像上显示一个徽章指示器,通常位于右下角。

PropTypeDefault
classNamestring-

AvatarGroup

AvatarGroup 组件以相互重叠的样式显示一组头像。

PropTypeDefault
classNamestring-

AvatarGroupCount

AvatarGroupCount 组件在头像组中显示一个计数指示器,通常用于展示额外头像的数量。

PropTypeDefault
classNamestring-

有关 Base UI Avatar 属性的更多信息,请参阅 Base UI 文档