affectUI › Components › Data display

Avatar

A person's picture or initials on a soft color of their own – rounded squares for workspaces, an agent's pixel mark that twinkles while it works, a status dot and a group that overlaps and ends in +N.

Free and open source (MIT). Install: npx shadcn@latest add https://www.affectui.com/r/avatar.json · Import from @/components/ui/avatar

When to use

  • A person next to their name: comments, members, assignees, the account menu
  • A workspace, team or org – shape="square" with its initial or logo
  • An AI agent – kind="agent" draws its own pixel mark in its color, twinkling while it works
  • Who is on something, in little space – AvatarGroup overlaps them and ends in +N

When not to use

  • A status on its own, without a person – use the Badge
  • A tool or app logo inside text – use an inline icon, like Tool Call Card does
  • Picking people – use the Tag Input or a Combobox, with an avatar in each option

Usage

import { Avatar, AvatarGroup } from "@/components/ui/avatar";

type Member = { id: string; name: string; picture?: string; online?: boolean };

export function Reviewers({ members }: { members: Member[] }) {
  return (
    <AvatarGroup size={24} max={4} aria-label={`${members.length} reviewers`}>
      {members.map((m) => (
        <Avatar key={m.id} seed={m.id} name={m.name} src={m.picture} status={m.online ? "online" : undefined} />
      ))}
      <Avatar kind="agent" seed="triage" name="Triage agent" />
    </AvatarGroup>
  );
}

Props

NameTypeDefaultDescription
namestringWho it is – the initials (first and last word), the accessible name and the color come from it. Left out: a person outline on gray
srcstringThe picture. The initials show while it loads and stay when it fails to load
size20 | 24 | 32 | 4032Width and height in pixels; the initials, the status dot and an agent's mark scale with it
shape"circle" | "square""circle" (agents: "square")circle for people · square, a rounded square, for workspaces, teams and agents
status"online" | "away" | "busy"A green, amber or red dot on the corner – added to the accessible name, e.g. "Mara Lindqvist, online"
kind"person" | "agent""person"agent: the agent's own 3×3 pixel mark on a white tile instead of initials – never a monogram. A src still shows its logo
seedstringnameWhat the color and an agent's pattern are made from – pass a stable id so a rename keeps them
colorstringblueagent: the mark's color – use the same color the agent has elsewhere
workingbooleanagent: the squares twinkle in a diagonal wave while it works
...span propsComponentProps<"span">className, style, title, aria-label, aria-hidden, ref and the rest go to the outer <span>
AvatarGroup maxnumber4How many show before the rest becomes +N (99+ above 99)
AvatarGroup size20 | 24 | 32 | 4032Sets the size of every Avatar in it and of the +N
AvatarGroup totalnumberHow many there are in all, when you pass only the first few – +N counts from it

Accessibility

  • With a name it is an image named after the person (role="img"), plus the status – "Jonas Weber, away"
  • Next to the written name, pass aria-hidden so screen readers don't say the name twice; without a name it is hidden on its own
  • The picture itself has an empty alt – the name is on the avatar, never read twice
  • AvatarGroup is a group: give it an aria-label like "9 reviewers"; +N reads "5 more"
  • The status color is never the only signal – it is part of the accessible name

Responsive

  • Initials are whole characters (Intl.Segmenter): accents, emoji with skin tones and flags never split; a name that starts with an emoji shows just that emoji
  • "III", "Jr." and the like don't make an initial, nor do brackets or quotes in front of a word – "Christopher Montgomery III" is CM
  • Right-to-left: the status dot and the overlap mirror to the other side
  • The group's ring and the status ring use --ui-avt-ring – set it to the background the avatars sit on (white by default)
  • Dark mode built in: switches when an ancestor (usually <html>) has the class dark or data-theme="dark"

Requirements

  • React 19

Related

  • Badge – A small status label that carries the color – six soft tones, a leading dot or icon, a live dot that pulses while something runs and a round count up to 99+
  • Collaboration Stream – What agents actually say to each other – a quiet chat where every message shows who it is from and who it is for, handoffs and questions for you tagged, files as chips that open a preview, a card with details under every message, and a composer to name agents with @ or answer a question
  • Comment Thread – One comment with replies – an assistant reports what it did, folds open details and answers @mentions
  • Tag Input – Several values in one field as chips – paste a whole list, a check per value, duplicates flash, Backspace and arrow keys to edit
  • Profile Menu – Account card with the signed-in user, menu actions and profile setup progress