Avatar — .mv-avatar
CSS avatar: an image layered over initials (automatic fallback when the image is missing or broken), sizes, round or square, tinted initials, status dot, counter; an overlapping group with a “+3” chip that spreads apart on hover.
| Category | Primitives |
|---|---|
| Type | CSS only (.mv-avatar) |
| Status | stable |
| Keywords | avatar, avatar-group, initials, status, presence, stack |
When to use
- A person or account needs a compact visual identity, with initials shown when the photo is missing or broken
- Presence must be shown next to a user, such as online, away, busy or offline
- Several collaborators or assignees must fit in a small space as an overlapping stack with a +N overflow chip
Avoid when
- A count or status label is the main information rather than an identity → use Badge instead
- The image is a product photo or content illustration rather than a person or account
Install
node scripts/add.mjs avatar --out ./src/marvelousAI agent with the Marvelous UI MCP server: install_components({ slugs: ["avatar"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).
Files copied (dependencies included): tokens/tokens.css, core/base.css, components/avatar/avatar.css, components/avatar/avatar.js.
Usage
Canonical markup — start from it and customize with attributes, data-* and CSS variables:
<div style="display:grid;gap:2rem;justify-items:center;--mv-avatar-ring:var(--mv-bg-subtle)">
<div style="display:flex;flex-wrap:wrap;gap:1rem;align-items:center;justify-content:center">
<span class="mv-avatar" data-size="xs"><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%23c4b5fd'/%3E%3Cstop offset='1' stop-color='%237c3aed'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='64' height='64' fill='url%28%23g%29'/%3E%3Cpath d='M10 66c1-12 10-19 22-19s21 7 22 19z' fill='%231e1b4b'/%3E%3Crect x='27' y='36' width='10' height='12' rx='4' fill='%23f1c7a8'/%3E%3Ccircle cx='32' cy='27' r='11' fill='%23f1c7a8'/%3E%3Cpath d='M20.5 26c0-8 5-13 11.5-13s11.5 5 11.5 13c-2-4-6-6.5-11.5-6.5S22.5 22 20.5 26z' fill='%233b2418'/%3E%3C/svg%3E" alt="Lena Moore"><span class="mv-avatar-fallback" aria-hidden="true">LM</span></span>
<span class="mv-avatar" data-size="sm"><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%2399f6e4'/%3E%3Cstop offset='1' stop-color='%230f766e'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='64' height='64' fill='url%28%23g%29'/%3E%3Cpath d='M10 66c1-12 10-19 22-19s21 7 22 19z' fill='%23f8fafc'/%3E%3Crect x='27' y='36' width='10' height='12' rx='4' fill='%23b98363'/%3E%3Ccircle cx='32' cy='27' r='11' fill='%23b98363'/%3E%3Cpath d='M20.5 26c0-8 5-13 11.5-13s11.5 5 11.5 13c-2-4-6-6.5-11.5-6.5S22.5 22 20.5 26z' fill='%231c1917'/%3E%3C/svg%3E" alt="Kwame Boateng"><span class="mv-avatar-fallback" aria-hidden="true">KB</span></span>
<span class="mv-avatar"><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%23fde68a'/%3E%3Cstop offset='1' stop-color='%23d97706'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='64' height='64' fill='url%28%23g%29'/%3E%3Cpath d='M10 66c1-12 10-19 22-19s21 7 22 19z' fill='%231f2937'/%3E%3Crect x='27' y='36' width='10' height='12' rx='4' fill='%23e7b590'/%3E%3Ccircle cx='32' cy='27' r='11' fill='%23e7b590'/%3E%3Cpath d='M20.5 26c0-8 5-13 11.5-13s11.5 5 11.5 13c-2-4-6-6.5-11.5-6.5S22.5 22 20.5 26z' fill='%237c2d12'/%3E%3C/svg%3E" alt="Isabel Moreno"><span class="mv-avatar-fallback" aria-hidden="true">IM</span><span class="mv-avatar-status" data-status="online"><span class="mv-sr-only">Online</span></span></span>
<span class="mv-avatar" data-size="lg"><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%23bae6fd'/%3E%3Cstop offset='1' stop-color='%232563eb'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='64' height='64' fill='url%28%23g%29'/%3E%3Cpath d='M10 66c1-12 10-19 22-19s21 7 22 19z' fill='%230f172a'/%3E%3Crect x='27' y='36' width='10' height='12' rx='4' fill='%23f3d1b5'/%3E%3Ccircle cx='32' cy='27' r='11' fill='%23f3d1b5'/%3E%3Cpath d='M20.5 26c0-8 5-13 11.5-13s11.5 5 11.5 13c-2-4-6-6.5-11.5-6.5S22.5 22 20.5 26z' fill='%23a16207'/%3E%3C/svg%3E" alt="Tom Grant"><span class="mv-avatar-fallback" aria-hidden="true">TG</span><span class="mv-avatar-status" data-status="away"><span class="mv-sr-only">Away</span></span></span>
<span class="mv-avatar" data-size="xl"><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%23fecdd3'/%3E%3Cstop offset='1' stop-color='%23e11d48'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='64' height='64' fill='url%28%23g%29'/%3E%3Cpath d='M10 66c1-12 10-19 22-19s21 7 22 19z' fill='%23fafaf9'/%3E%3Crect x='27' y='36' width='10' height='12' rx='4' fill='%238d5a3b'/%3E%3Ccircle cx='32' cy='27' r='11' fill='%238d5a3b'/%3E%3Cpath d='M20.5 26c0-8 5-13 11.5-13s11.5 5 11.5 13c-2-4-6-6.5-11.5-6.5S22.5 22 20.5 26z' fill='%23111827'/%3E%3C/svg%3E" alt="Sofia Nguyen"><span class="mv-avatar-fallback" aria-hidden="true">SN</span><span class="mv-avatar-status" data-status="busy"><span class="mv-sr-only">Busy</span></span></span>
<span class="mv-avatar" data-size="xl" data-shape="square"><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%23c4b5fd'/%3E%3Cstop offset='1' stop-color='%237c3aed'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='64' height='64' fill='url%28%23g%29'/%3E%3Cpath d='M10 66c1-12 10-19 22-19s21 7 22 19z' fill='%231e1b4b'/%3E%3Crect x='27' y='36' width='10' height='12' rx='4' fill='%23f1c7a8'/%3E%3Ccircle cx='32' cy='27' r='11' fill='%23f1c7a8'/%3E%3Cpath d='M20.5 26c0-8 5-13 11.5-13s11.5 5 11.5 13c-2-4-6-6.5-11.5-6.5S22.5 22 20.5 26z' fill='%233b2418'/%3E%3C/svg%3E" alt="Lena Moore"><span class="mv-avatar-fallback" aria-hidden="true">LM</span><span class="mv-avatar-status" data-status="online" data-side="top"><span class="mv-sr-only">Online</span></span></span>
</div>
<div style="display:flex;flex-wrap:wrap;gap:1rem;align-items:center;justify-content:center">
<span class="mv-avatar" data-size="lg" data-variant="tinted" role="img" aria-label="Alice Lambert"><span class="mv-avatar-fallback" aria-hidden="true">AL</span></span>
<span class="mv-avatar" data-size="lg" data-variant="tinted" style="--mv-avatar-hue:160" role="img" aria-label="Marcus Chen"><span class="mv-avatar-fallback" aria-hidden="true">MC</span></span>
<span class="mv-avatar" data-size="lg" data-variant="tinted" style="--mv-avatar-hue:40" role="img" aria-label="Julia Diaz"><span class="mv-avatar-fallback" aria-hidden="true">JD</span></span>
<span class="mv-avatar" data-size="lg"><img src="data:image/png;base64,AAAA" alt="Priya Rao"><span class="mv-avatar-fallback" aria-hidden="true">PR</span><span class="mv-avatar-status" data-status="offline"><span class="mv-sr-only">Offline</span></span></span>
<span class="mv-avatar" data-size="lg" role="img" aria-label="Guest"><span class="mv-avatar-fallback" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="8" r="4"/><path d="M4 21a8 8 0 0 1 16 0"/></svg></span></span>
<span class="mv-avatar" data-size="lg" data-shape="square"><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%2399f6e4'/%3E%3Cstop offset='1' stop-color='%230f766e'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='64' height='64' fill='url%28%23g%29'/%3E%3Cpath d='M10 66c1-12 10-19 22-19s21 7 22 19z' fill='%23f8fafc'/%3E%3Crect x='27' y='36' width='10' height='12' rx='4' fill='%23b98363'/%3E%3Ccircle cx='32' cy='27' r='11' fill='%23b98363'/%3E%3Cpath d='M20.5 26c0-8 5-13 11.5-13s11.5 5 11.5 13c-2-4-6-6.5-11.5-6.5S22.5 22 20.5 26z' fill='%231c1917'/%3E%3C/svg%3E" alt="Kwame Boateng"><span class="mv-avatar-fallback" aria-hidden="true">KB</span><span class="mv-avatar-badge" aria-label="3 notifications">3</span></span>
<span class="mv-avatar" data-size="lg"><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%23fde68a'/%3E%3Cstop offset='1' stop-color='%23d97706'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='64' height='64' fill='url%28%23g%29'/%3E%3Cpath d='M10 66c1-12 10-19 22-19s21 7 22 19z' fill='%231f2937'/%3E%3Crect x='27' y='36' width='10' height='12' rx='4' fill='%23e7b590'/%3E%3Ccircle cx='32' cy='27' r='11' fill='%23e7b590'/%3E%3Cpath d='M20.5 26c0-8 5-13 11.5-13s11.5 5 11.5 13c-2-4-6-6.5-11.5-6.5S22.5 22 20.5 26z' fill='%237c2d12'/%3E%3C/svg%3E" alt="Isabel Moreno"><span class="mv-avatar-fallback" aria-hidden="true">IM</span><span class="mv-avatar-status" data-status="online" data-pulse><span class="mv-sr-only">Online</span></span></span>
</div>
<div style="display:flex;flex-wrap:wrap;gap:2.5rem;align-items:center;justify-content:center">
<div class="mv-avatar-group" role="group" aria-label="Project members">
<span class="mv-avatar"><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%23c4b5fd'/%3E%3Cstop offset='1' stop-color='%237c3aed'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='64' height='64' fill='url%28%23g%29'/%3E%3Cpath d='M10 66c1-12 10-19 22-19s21 7 22 19z' fill='%231e1b4b'/%3E%3Crect x='27' y='36' width='10' height='12' rx='4' fill='%23f1c7a8'/%3E%3Ccircle cx='32' cy='27' r='11' fill='%23f1c7a8'/%3E%3Cpath d='M20.5 26c0-8 5-13 11.5-13s11.5 5 11.5 13c-2-4-6-6.5-11.5-6.5S22.5 22 20.5 26z' fill='%233b2418'/%3E%3C/svg%3E" alt="Lena Moore"><span class="mv-avatar-fallback" aria-hidden="true">LM</span></span>
<span class="mv-avatar"><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%2399f6e4'/%3E%3Cstop offset='1' stop-color='%230f766e'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='64' height='64' fill='url%28%23g%29'/%3E%3Cpath d='M10 66c1-12 10-19 22-19s21 7 22 19z' fill='%23f8fafc'/%3E%3Crect x='27' y='36' width='10' height='12' rx='4' fill='%23b98363'/%3E%3Ccircle cx='32' cy='27' r='11' fill='%23b98363'/%3E%3Cpath d='M20.5 26c0-8 5-13 11.5-13s11.5 5 11.5 13c-2-4-6-6.5-11.5-6.5S22.5 22 20.5 26z' fill='%231c1917'/%3E%3C/svg%3E" alt="Kwame Boateng"><span class="mv-avatar-fallback" aria-hidden="true">KB</span></span>
<span class="mv-avatar"><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%23fde68a'/%3E%3Cstop offset='1' stop-color='%23d97706'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='64' height='64' fill='url%28%23g%29'/%3E%3Cpath d='M10 66c1-12 10-19 22-19s21 7 22 19z' fill='%231f2937'/%3E%3Crect x='27' y='36' width='10' height='12' rx='4' fill='%23e7b590'/%3E%3Ccircle cx='32' cy='27' r='11' fill='%23e7b590'/%3E%3Cpath d='M20.5 26c0-8 5-13 11.5-13s11.5 5 11.5 13c-2-4-6-6.5-11.5-6.5S22.5 22 20.5 26z' fill='%237c2d12'/%3E%3C/svg%3E" alt="Isabel Moreno"><span class="mv-avatar-fallback" aria-hidden="true">IM</span></span>
<span class="mv-avatar"><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%23bae6fd'/%3E%3Cstop offset='1' stop-color='%232563eb'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='64' height='64' fill='url%28%23g%29'/%3E%3Cpath d='M10 66c1-12 10-19 22-19s21 7 22 19z' fill='%230f172a'/%3E%3Crect x='27' y='36' width='10' height='12' rx='4' fill='%23f3d1b5'/%3E%3Ccircle cx='32' cy='27' r='11' fill='%23f3d1b5'/%3E%3Cpath d='M20.5 26c0-8 5-13 11.5-13s11.5 5 11.5 13c-2-4-6-6.5-11.5-6.5S22.5 22 20.5 26z' fill='%23a16207'/%3E%3C/svg%3E" alt="Tom Grant"><span class="mv-avatar-fallback" aria-hidden="true">TG</span></span>
<button class="mv-avatar-more" aria-label="Show 3 more members">+3</button>
</div>
<div style="display:flex;align-items:center;gap:.75rem">
<div class="mv-avatar-group" data-size="sm">
<span class="mv-avatar"><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%23fecdd3'/%3E%3Cstop offset='1' stop-color='%23e11d48'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='64' height='64' fill='url%28%23g%29'/%3E%3Cpath d='M10 66c1-12 10-19 22-19s21 7 22 19z' fill='%23fafaf9'/%3E%3Crect x='27' y='36' width='10' height='12' rx='4' fill='%238d5a3b'/%3E%3Ccircle cx='32' cy='27' r='11' fill='%238d5a3b'/%3E%3Cpath d='M20.5 26c0-8 5-13 11.5-13s11.5 5 11.5 13c-2-4-6-6.5-11.5-6.5S22.5 22 20.5 26z' fill='%23111827'/%3E%3C/svg%3E" alt="Sofia Nguyen"><span class="mv-avatar-fallback" aria-hidden="true">SN</span></span>
<span class="mv-avatar"><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%23bae6fd'/%3E%3Cstop offset='1' stop-color='%232563eb'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='64' height='64' fill='url%28%23g%29'/%3E%3Cpath d='M10 66c1-12 10-19 22-19s21 7 22 19z' fill='%230f172a'/%3E%3Crect x='27' y='36' width='10' height='12' rx='4' fill='%23f3d1b5'/%3E%3Ccircle cx='32' cy='27' r='11' fill='%23f3d1b5'/%3E%3Cpath d='M20.5 26c0-8 5-13 11.5-13s11.5 5 11.5 13c-2-4-6-6.5-11.5-6.5S22.5 22 20.5 26z' fill='%23a16207'/%3E%3C/svg%3E" alt="Tom Grant"><span class="mv-avatar-fallback" aria-hidden="true">TG</span></span>
<span class="mv-avatar" data-variant="tinted" style="--mv-avatar-hue:160" role="img" aria-label="Marcus Chen"><span class="mv-avatar-fallback" aria-hidden="true">MC</span></span>
</div>
<span style="font-size:.875rem;color:var(--mv-fg-muted)"><strong style="color:var(--mv-fg);font-weight:500">Sofia, Marcus</strong> and 12 others reacted</span>
</div>
</div>
</div>API
Attributes
| Name | Type | Default | Description |
|---|---|---|---|
data-size | xs | sm | lg | xl | 2xl | (md = 2.5rem) | On .mv-avatar, .mv-avatar-more or .mv-avatar-group. |
data-shape | square | Rounded corners instead of a circle. | |
data-variant | tinted | Initials colored from --mv-avatar-hue. | |
data-ring | boolean | Accent ring (highlight). | |
data-status | online | away | busy | offline | online | On .mv-avatar-status. |
data-side | top | On .mv-avatar-status: top corner. | |
data-pulse | boolean | On .mv-avatar-status: pulsing halo (off with reduced motion). | |
data-spread | false | On .mv-avatar-group: disables the spread on hover. | |
data-mv-state | loading | loaded | error | Set on the <img> by avatar.js (fade-in on load, fallback on error). |
CSS classes
| Name | Description |
|---|---|
mv-avatar | Container: <img> + .mv-avatar-fallback stacked (image on top). |
mv-avatar-fallback | Initials or icon (aria-hidden); visible until the image has loaded. |
mv-avatar-status | Presence dot (include .mv-sr-only text). |
mv-avatar-badge | Corner counter (aria-label recommended). |
mv-avatar-group | Overlapping stack with a ring; spreads apart and lifts the hovered avatar (and its neighbors). |
mv-avatar-more | “+N” overflow chip (span or button) inside a group. |
CSS variables
| Name | Default | Description |
|---|---|---|
--mv-avatar-size | 2.5rem | Size (inherited: can be set on a parent). |
--mv-avatar-radius | 50% | Radius. |
--mv-avatar-ring | var(--mv-bg) | Color of the separating ring (= page background). |
--mv-avatar-bg / -fg | Fallback colors. | |
--mv-avatar-hue | var(--mv-accent-h) | Hue of the initials in the tinted variant. |
--mv-avatar-overlap / -overlap-hover | -0.28 / -0.1 | Group overlap (fraction of the size), at rest and on hover. |
Accessibility
With an image: alt carries the name and the initials are aria-hidden; a broken image stays in the accessibility tree (it is only made invisible). Without an image: role="img" + aria-label on .mv-avatar. Status: .mv-sr-only text inside the dot (color alone is not enough). Group: role="group" + aria-label; make the +N chip a <button> with an aria-label if it opens the list. Lift and halo are disabled with reduced motion.