Avatars

How the Avatars works with a keyboard and assistive tech, and where it stands against WCAG 2.2 AA.

FreeReact and Vue
AAWCAG 2.2 target
19/24contrast pairs passing
1keyboard interactions

The Avatar is one image with a name. The outer element carries role="img" and an aria-label built from the person's name, with ", online" and ", verified" added when those marks show; the photo, initials and glyph inside are hidden from assistive tech so the name is read once. It is not interactive.

Keyboard#

Tab

Passes over the avatar: it is not focusable. If an avatar opens a profile, wrap it in a link or button, and that control takes focus.

Semantics#

role="img"

The whole avatar, disc and badges together, is one image.

Always
aria-label

The person's name, from name, persona or alt. Pass ariaLabel to override it, for example "Your account".

Always
<img alt="">

The picture itself is decorative. The name lives on the outer element.

Image, cut-out, memoji, illustration
, online / , verified

Appended to the label, so the dot and rosette are not colour-only signals.

showOnlineStatus, showVerifiedBadge
aria-hidden

The rosette SVG is hidden; its meaning is in the label.

Verified rosette

Colour contrast#

Every variant and state has to meet WCAG 2.2 Level AA. Measure the colours as they land on screen: a translucent hover or press wash over whatever sits behind it.

4.5:1

Initials · Text

Initials against the persona's disc. Satoshi Bold at 24px and up (sizes 72 to 100) counts as large text and needs 3:1; at 56 and below (18px and smaller) it needs 4.5:1. Initials are only a picture of the name, but they are often the only thing a sighted user reads, so treat them as text.

WCAG 1.4.3 Contrast (Minimum) ↗
3:1

Verified check and online dot · Badges

Graphics that carry meaning need 3:1 against what is next to them. The meaning is also in the accessible name, so the label, not the colour, is what a screen reader user gets.

WCAG 1.4.11 Non-text Contrast ↗WCAG 1.4.1 Use of Color ↗
Required

Text alternative · Every variant

An avatar that stands for a person needs that person's name. Beside a visible name it is redundant; give it ariaLabel="" only in markup that hides it with aria-hidden, so the name is not read twice.

WCAG 1.1.1 Non-text Content ↗

Measured contrast#

Initials against each persona's disc, and the rosette's check against the rosette, from the persona colours the component uses. Initials are held to 4.5:1; the check is a graphic and is held to 3:1. 5 of 24 pairs fall below their minimum (4.5:1 for text, 3:1 for graphics) and are marked in amber.

Persona · styleInitialsVerified check
Ethan Cole · Text13.99passes3.63passes
Morgan Philips · Text14.06passes3.63passes
Noah Reed · Text14.12passes3.63passes
Khadija Alaa · Text9.29passes3.63passes
Liam Hawk · Text3.56below the minimum3.63passes
Cara Brook · Text3.90below the minimum3.63passes
Shima Hayes · Text17.26passes3.63passes
Frieren Bloodfallen · Text15.40passes3.63passes
Ryan Mills · Text3.02below the minimum3.02passes
Aroura Flaps · Text2.66below the minimum3.63passes
Theo Wright · Text1.63below the minimum3.63passes
Yellena Thorn · Text5.92passes15.53passes

Motion#

  • The avatar does not animate.

Checklist#

Every avatar has the person's name, through name, persona or ariaLabel. A generic "User" tells nobody anything.

When the avatar sits beside the visible name, hide it from assistive tech (aria-hidden on a wrapper) so the name is not read twice.

Initials on Liam Hawk, Cara Brook, Ryan Mills, Aroura Flaps and Theo Wright fall below 4.5:1, and Theo Wright's white on #ffbe71 is under 3:1 at any size. Darken the ink or the disc before using those personas with initials at 56px and below.

If the avatar is clickable, put the link or button around it; do not add a click handler to the role="img" element.