Avatar

Represent a person, a team or a thing with an image, initials or an icon, with an indicator on a corner or an edge, a ring and group stacking that hold at every size.

Accessibility

An avatar is a picture, not a control. Most of the work here is deciding what it should be announced as, and what has to sit around it when it needs to be operable.

Avatar is not a control

AvatarProps is a closed list and it does not extend HTMLAttributes: there is no role, tabIndex, aria-label or key handler to put beside an onClick. A bare clickable avatar is unreachable by keyboard and unnamed to a screen reader, and no attribute at the call site can fix it.
  • Put it inside a Button, which brings the element, the tab stop, the focus ring and Enter/Space with it.
  • Or use Button's own avatar prop, which renders the same face inside a real button with the gaps already correct.
  • Name the action on that button, not only the person: “Open your account menu”, “Remove Ada Lovelace from this project”.
  • The same applies to anything in the indicator slot. A camera or remove affordance in the corner is a Button; a presence dot is a plain span and must not be focusable.

What it is announced as

The accessible name depends on which content route the avatar took, and only one of the three has a name channel of its own.
  • Image. alt is forwarded to the underlying <img>. Give every image avatar one: there is no text to fall back on, so without it the avatar is announced as an unlabeled image.
  • Image beside its own name. Use alt="", which drops it from the accessibility tree. The picture carries nothing the text next to it does not already say, and repeating it is noise.
  • Initials. They are real text, so they are read out, letter by letter or as a word depending on the reader. That is rarely useful on its own: keep the full name visible, or wrap the avatar in an element that carries it.
  • Icon. alt only applies to the src branch, so an icon avatar has no name at all. Its meaning has to come from the row it sits in, or from a label on a wrapping element.

Groups and tooltips

  • A stacked group hides the names visually, so a Tooltip per avatar is the usual fix. The Tooltip wraps the Avatar, because it needs a child to attach a trigger to and AvatarProps carries no title.
  • A Tooltip is not a label. It does not exist for touch and is not reliably announced, so the names still have to be reachable somewhere: the overflow popover, a nearby list, or text.
  • The +n overflow chip announces its own text, which is a count and not a list. Let its popover carry the names.
  • In a picker, give each person one focus stop, not one per avatar plus one per label.

Status and presence

Color alone is not an accessible signal, and a presence dot is the most common place that rule gets broken.
  • Say the state three ways where it matters: the hue, the shape of the glyph, and words. Two people in ten cannot separate the first from a neighboring hue.
  • Use the four semantic status colors rather than palette shades, so a presence dot matches every Alert, Tag and Result in the product.
  • If the state can change while the page is open, announce the change in a live region. Nothing about repainting a dot is announced on its own.

Contrast

  • The colorless default is colorFillSecondary under colorTextSecondary, which clears WCAG AA with room in both modes. Ant Design's own white label on colorTextPlaceholder is unreadable in light mode.
  • variant="solid" puts white on the ramp's mid tone and misses AA on ten of the twelve presets, with gold and yellow the worst. Use filled on a warm hue, or a neutral ramp, whose solid fill is darker.
  • Initials are small text at every size, because textFontSize does not grow with the named sizes. Check them at the smallest size you ship, not at the largest.
  • The ring is transparent outside a group. If you use it to carry a state, give it a color you have checked against both the page and the avatar.
  • Re-check both modes after any token change. The two ramps darken in opposite directions.

Motion and decoration

  • Gate hover and expand animations behind motion-safe:. An expandable group that fans out on hover is the kind of motion a reader may have asked to turn off.
  • A grayscale treatment is decoration, not information. If it means “inactive”, say so somewhere that is readable.
  • A story ring that means “unseen” needs a second signal too, for the same reason.