Skip to main content

Avatar

An avatar shows an image, or the initials from name while it loads and after it fails. The root is role="img" named by alt / name plus the status, so everything drawn inside is decorative. sm / md / lg are the control heights, so avatars line up with the controls beside them.

import Avatar from '@zuilib/components/avatar'

Image, initials, fallback

Without src (or after a load error) the initials show on the muted surface; fallback overrides them; with nothing to show, a person icon.

Loading example

Sizes and shapes

Loading example

Status

Each status is a shape as well as a colour: online a solid disc, away a crescent, busy a disc with a bar, offline a hollow ring. The status is appended to the accessible name and shown as the dot's title.

Loading example

Group

Avatar.Group overlaps its avatars, passes down size / shape, and rings each one in the surface colour (--avatar-ring, falling back to --background). max collapses the rest into a +N avatar named for assistive technology and titled with the hidden names.

Loading example

Props

AvatarProps extends span props (minus children).

PropTypeDefaultDescription
srcstringImage URL. The fallback shows until it loads; on error it stays. A failed URL is not retried until src changes or the avatar remounts
namestringSource of the initials ("Ada Lovelace"AL) and the default alt
altstringnameAccessible name (role="img"). '' makes the avatar decorative, status included; with neither and no aria-label / aria-labelledby it is decorative too
fallbackReactNodeinitials, else a person iconShown when there is no image; decorative
size'xs' | 'sm' | 'md' | 'lg' | 'xl''md'Inherits Avatar.Group
shape'circle' | 'square''circle'Inherits Avatar.Group. A radius in className reaches the image too
status'online' | 'offline' | 'busy' | 'away'Presence dot on the bottom-end corner
statusLabelstringcapitalised statusAppended to the accessible name and shown as the dot's title
imgPropsOmit<ImgHTMLAttributes, 'src' | 'alt' | 'onLoad' | 'onError'>Spread on the <img> (loading, srcSet, crossOrigin, …)
classNamestringMerged last, after the size and shape classes

Avatar.Group

div props plus:

PropTypeDefaultDescription
size'xs' | 'sm' | 'md' | 'lg' | 'xl''md'Size of every avatar inside; an avatar's own size wins
shape'circle' | 'square''circle'Shape of every avatar inside; an avatar's own shape wins
maxnumberHow many to show; the rest collapse into a +N avatar
overflowLabel(hidden: number, names: string[]) => string`${hidden} more: ${names}`Accessible name of the +N avatar
classNamestringMerged last onto the root

getInitials(name) is a named export.

Slots

SlotElementNotes
[data-slot="avatar"]spanRoot. Also data-size, data-shape, data-status, data-state="loading" | "loaded" | "error" | "fallback"; the overflow avatar adds data-overflow
[data-slot="avatar-image"]imgalt="", aria-hidden
[data-slot="avatar-initials"]spanInitials from name
[data-slot="avatar-fallback"]spanThe fallback node
[data-slot="avatar-icon"]svgPerson icon when nothing else is available
[data-slot="avatar-status"]spandata-status; aria-hidden
[data-slot="avatar-group"]divrole="group", data-size, data-shape
/* Consumer CSS: ring avatars in the card colour when they sit on a card */
[data-slot="card"] {
--avatar-ring: var(--card);
}

Tokens

TokenUsed for
--control-height-sm/md/lgBox per size; xs / xl step one --spacing notch outside
--muted, --muted-foregroundFallback surface and text
--radius-mdThe square shape
--avatar-ring (falls back to --background)Group ring and the status dot cut-out
--success, --warning, --destructive, --destructive-foregroundStatus dot colours

Accessibility

  • The root is role="img" with aria-label from alt (or name) and the status; the <img> inside has alt="" and aria-hidden.
  • alt="", or no name at all, makes the avatar aria-hidden; aria-labelledby keeps it named.
  • Status is never colour-only: each state has its own shape, and the status text is part of the accessible name and the dot's title.
  • Avatar.Group is role="group"; the +N avatar is named by overflowLabel (default "N more: names").
  • A cached image that finishes before hydration is read off the element, so the fallback does not flash over a loaded picture.
  • Badge: the same status colours as text.
  • Skeleton: a placeholder while the whole row loads.
  • Card: set --avatar-ring: var(--card) to blend group rings in.