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.

CategoryPrimitives
TypeCSS only (.mv-avatar)
Statusstable
Keywordsavatar, avatar-group, initials, status, presence, stack

When to use

Avoid when

Install

node scripts/add.mjs avatar --out ./src/marvelous

AI 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

NameTypeDefaultDescription
data-sizexs | sm | lg | xl | 2xl(md = 2.5rem)On .mv-avatar, .mv-avatar-more or .mv-avatar-group.
data-shapesquareRounded corners instead of a circle.
data-varianttintedInitials colored from --mv-avatar-hue.
data-ringbooleanAccent ring (highlight).
data-statusonline | away | busy | offlineonlineOn .mv-avatar-status.
data-sidetopOn .mv-avatar-status: top corner.
data-pulsebooleanOn .mv-avatar-status: pulsing halo (off with reduced motion).
data-spreadfalseOn .mv-avatar-group: disables the spread on hover.
data-mv-stateloading | loaded | errorSet on the <img> by avatar.js (fade-in on load, fallback on error).

CSS classes

NameDescription
mv-avatarContainer: <img> + .mv-avatar-fallback stacked (image on top).
mv-avatar-fallbackInitials or icon (aria-hidden); visible until the image has loaded.
mv-avatar-statusPresence dot (include .mv-sr-only text).
mv-avatar-badgeCorner counter (aria-label recommended).
mv-avatar-groupOverlapping 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

NameDefaultDescription
--mv-avatar-size2.5remSize (inherited: can be set on a parent).
--mv-avatar-radius50%Radius.
--mv-avatar-ringvar(--mv-bg)Color of the separating ring (= page background).
--mv-avatar-bg / -fgFallback colors.
--mv-avatar-huevar(--mv-accent-h)Hue of the initials in the tinted variant.
--mv-avatar-overlap / -overlap-hover-0.28 / -0.1Group 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.