Avatar group
Stacked overlapping avatars that represent multiple people in a compact space. Max four avatars are shown; any additional members collapse into a muted overflow circle with a +N count. Used in expense cards, split summaries, and group headers.
Variants
Avatars stack right-to-left using flex-direction: row-reverse so the first person (usually "You") sits on the left visually. Each avatar gets a 2px paper-colored ring to separate the overlapping circles.
When more than 4 people are in a group, cap at 4 visible avatars and show +N in a muted circle on the right. Never show 5 or more avatars without an overflow circle.
Sizes
| Size | Avatar class | Overflow class | Overlap | Use case |
|---|---|---|---|---|
| Large | .avatar-lg | .avatar-group-overflow.avatar-lg | −8px | Group header, member list header |
| Medium | .avatar-md | .avatar-group-overflow.avatar-md | −8px | Expense cards — default |
| Small | .avatar-sm | .avatar-group-overflow.avatar-sm | −8px | Dense feed rows, tab bar |
States
| State | Visual change | When |
|---|---|---|
| Default | Full opacity, paper ring on each avatar | — |
| Settled / dimmed | 40% opacity on the whole group | All members have settled for this expense |
On dark surfaces
On dark surfaces, the separator ring changes from --s-paper to --dark-canvas so the avatars still feel separated. The overflow circle switches to --dark-elevated background with --dark-text-2 text. Add the .on-dark class to the nearest ancestor.
Anatomy
| Part | Element | Notes |
|---|---|---|
| Container | .avatar-group | flex-direction: row-reverse so DOM order = priority order but visual stacking = left-first. |
| Avatar | .avatar with size and color classes | Max 4 rendered. Ring: box-shadow: 0 0 0 2px --s-paper. On dark: --dark-canvas. |
| Overflow | .avatar-group-overflow | Shows +N where N = total members − 4. Muted background, body font. |
| Separator ring | box-shadow | 2px solid ring in page background color. Creates visual separation between overlapping circles. |
Usage
-md in cards, -lg in headers, -sm in dense rows.
Accessibility
aria-label with the person's full name. The overflow element needs aria-label="N more people" (e.g. "3 more people"). Wrap the whole group in a <div role="group" aria-label="Goa trip members: Aarav, Priya, Rohan and 3 more"> so the full list is announced in one pass.
aria-label or a visually hidden <span> — not inferred from the visible "+3" alone.
Code
HTML
<!-- 4 members + overflow --> <div class="avatar-group" role="group" aria-label="Goa trip: Aarav, Priya, Rohan, Kabir and 3 more"> <!-- Overflow last in DOM = rightmost visually --> <span class="avatar-group-overflow avatar-md" aria-label="3 more people">+3</span> <span class="avatar avatar-md avatar-butter" aria-label="Kabir">K</span> <span class="avatar avatar-md avatar-teal" aria-label="Rohan">R</span> <span class="avatar avatar-md avatar-coral" aria-label="Priya">P</span> <!-- Current user first in DOM = leftmost visually --> <span class="avatar avatar-md avatar-you" aria-label="Aarav (you)">A</span> </div>
CSS classes
| Class | Purpose |
|---|---|
.avatar-group | Container — row-reverse flex, establishes stacking context |
.avatar-group-overflow | +N circle — muted background, body font, paper ring |
.on-dark (ancestor) | Switches ring and overflow to dark-surface colors |
Design tokens used
| Token | Value | Role |
|---|---|---|
--s-paper | #FBF8F0 | Separator ring on light surfaces |
--dark-canvas | #1E1A16 | Separator ring on dark surfaces |
--s-warm | #F1E9D5 | Overflow circle background |
--dark-elevated | #2A2521 | Overflow circle background on dark |
--ink-body | #4A443D | Overflow circle text |
--dark-text-2 | rgba(251,248,240,0.70) | Overflow text on dark |
Gagan's variant Gagan
Called AvatarStack in Gagan's prototypes. Same overlap concept but uses hardcoded hex colors inline instead of --av-* tokens. No separator ring (box-shadow omitted). Overflow uses a muted style, same as the DS.
AvatarStack uses #D6EAE2 / #0A5F4F inline instead of --av-teal / --av-you tokens. This breaks dark-mode overrides and makes the palette impossible to update in one place. Gagan's version should adopt --av-* tokens.
See it in context
Interactive prototype — this component is live below. Tap, swipe, and drag to explore.