Vetrix Docs

Avatar alt-text convention

Applies to every user display that includes an avatar (comment headers, collaborator/member lists, activity streams, profile headers, user menu triggers, watcher stacks, …).

The rule

One rule, two modes:

  1. Name-adjacent → <img alt=""> The username (or display name) is already rendered next to the avatar. The avatar is decorative — a screen reader would double-speak the identity. This is the common case.

  2. Standalone → <img alt="{username}"> The avatar stands on its own with no adjacent text name. The alt is the username so assistive tech can still identify the user.

If the parent element carries its own accessible name (e.g. a <button> with aria-label="User menu for {username}"), the avatar inside is decorative — use the default (name-adjacent) mode. The button's accessible name owns the identity; duplicating it on the inner <img> just makes the screen reader repeat itself.

Use the primitive

@/components/ui/Avatar enforces the rule via a standalone prop:

import { Avatar } from '@/components/ui'

// Name-adjacent (default) — alt=""
<div className="flex items-center gap-2">
  <Avatar src={user.avatar_url} username={user.username} size={28} />
  <span>{user.username}</span>
</div>

// Standalone — alt={username}
<Avatar
  src={user.avatar_url}
  username={user.username}
  standalone
  size={32}
/>

When src is empty/null the primitive renders an initial-letter fallback disc. In standalone mode the disc gets role="img" + aria-label={username} so the contract holds whether or not the user has uploaded a photo.

Hand-rolled <img>? Apply the rule directly

If for some reason you can't use the primitive (e.g. a larger preview in a settings/cropper flow), apply the rule by hand and leave a short comment next to the alt explaining which mode applies:

{/* Avatar alt-text: username is rendered adjacently, avatar is decorative. */}
<Image src={avatarUrl} alt="" width={64} height={64} className="…" />

The regression test at web/src/__tests__/components/ui/AvatarAltConvention.test.ts scans web/src/ for every <img> / <Image> whose src references an avatar URL and asserts the alt attribute is either empty or an interpolated expression (i.e. alt={...}). A raw literal like alt="user photo" will fail the build.