Avatars
Summary
Identity marks in seven sizes, 16 to 128px. People are round; projects and other
non-person entities use the squared variant. Content is either an
<img> (cover-fitted) or initials text.
When to use
| Size | Use it for |
|---|---|
-xsmall 16px | Inline with text: activity feeds, mentions. |
-small 24px | Dense lists and table cells. |
-medium 32px (default) | Navbars, comments, cards. |
-large 48px | Profile headers, people pickers. |
-xlarge 64 / -xxlarge 96 / -xxxlarge 128px | Profile pages and detail headers. |
Examples
Image vs initials
Prefer the photo; initials are the fallback, not a style choice.
Build them from the first letters of the given and family name —
one or two characters, never more (the disc doesn't fit three,
at any size). The <img> is cover-fitted
(object-fit: cover), so any aspect ratio crops to
the centre and no pre-cropping is needed.
Accessible naming follows one question: is the name printed
next to the avatar? If not (the avatar is the only
identification), the image's alt carries the name
(initials, being real text, are already read aloud). If yes, the
avatar is redundant decoration: use alt="" on the
image, or aria-hidden="true" on the initials form, so
the name isn't announced twice.
Sizing
Pick from the seven fixed steps. Don't free-size with inline
styles; the scale exists so avatars align across tables, feeds
and headers. Each size step also scales the initials type (8px at
-xsmall up to 42px at -xxxlarge), so the
two content forms stay interchangeable at every size — a roster
can mix photos and initials without rag. Guidance per step is in
the When to use table; -square combines
with every size.
HTML
An image avatar, with the name in alt when the avatar is
the only identification:
<span class="soma-avatar soma-avatar-medium">
<img src="…" alt="Anna Nelson" />
</span>
The initials fallback, real text styled onto the tinted disc:
<span class="soma-avatar soma-avatar-medium soma-avatar-initials">AN</span>
Squared, for a project or app (initials or image alike):
<span class="soma-avatar soma-avatar-large soma-avatar-square soma-avatar-initials">NW</span>
Next to the printed name the avatar is decoration — silence it for screen readers:
<span class="soma-avatar soma-avatar-small soma-avatar-initials"
aria-hidden="true">AN</span>
<a href="/people/anna">Anna Nelson</a>
CSS classes
| Class | Effect |
|---|---|
.soma-avatar | Base: round, 32px, tinted disc; an <img> child is cover-fitted. |
.soma-avatar-xsmall / -small / -medium / -large | 16 / 24 / 32 / 48px. |
.soma-avatar-xlarge / -xxlarge / -xxxlarge | 64 / 96 / 128px, for profile pages and detail headers. |
.soma-avatar-initials | Styles the text content as initials on the tinted disc; the type size follows the size step. |
.soma-avatar-square | Rounded-square shape for projects/apps. Combines with every size. |
JavaScript
None shipped; avatars are CSS-only. The one pattern worth wiring is the image-failure fallback: when a photo 404s, swap the avatar to its initials form instead of showing a broken image.
function initialsFallback(img, initials) {
const swap = () => {
const avatar = img.closest('.soma-avatar');
avatar.classList.add('soma-avatar-initials');
avatar.textContent = initials; // replaces the <img>
};
// The image may have failed before this code ran — check, then listen.
if (img.complete && img.naturalWidth === 0) swap();
else img.addEventListener('error', swap, { once: true });
}
The live example above, exactly as this page wires it:
const img = document.getElementById('avatar-fallback-img');
const swap = () => {
const avatar = img.closest('.soma-avatar');
avatar.classList.add('soma-avatar-initials');
avatar.textContent = 'MD';
};
if (img.complete && img.naturalWidth === 0) swap();
else img.addEventListener('error', swap, { once: true });