Designer view

Avatar Group

A composition of avatar instances rendered as a stack or grid with bounded count and an overflow indicator (+N) for collaborator lists, attribution rows, and shared-document headers. Codifies the canonical overflow contract — counts beyond `max` collapse into a single indicator tile — and the disclosure pattern for revealing the full member list.

Also called Avatar stack Stacked avatars User stack Member list

When to use

Use

For representing a group of users, organisations, or entities in a bounded surface — collaborator strips on shared documents, member rows in team headers, attribution lines on commits, and viewer lists in real-time editors. Pair with a textual count or member- list affordance when the overflow indicator is the only access path to the collapsed members. Stack layout suits dense inline contexts (header strips, attribution lines); grid layout suits member-management surfaces (settings pages, organisation rosters).

Avoid

For a single-entity representation — that is `Avatar`, not a group of one. For a long member list with metadata (presence, role, activity timestamp) — that is a list of `ListItem` rows with a leading avatar slot, not a stack. For unbounded counts on dense surfaces — set a sensible `max` (typically 3-5) so the visual weight stays predictable. For decorative groupings without identity meaning — that is layered tiles, not avatars.

Versus related

  • avatar

    `Avatar` is the single-entity representation primitive that Avatar Group composes; Avatar Group is the bounded set representation. A single Avatar is "this person"; an Avatar Group is "this group of people". When the count is one, render Avatar directly — Avatar Group with one child is an anti-pattern.

  • list-item

    `ListItem` is a one-dimensional row with leading avatar + primary text + secondary text + trailing affordances; Avatar Group is a bounded visual unit that collapses identity into a compact strip. ListItem suits member-management with metadata (presence, role, activity); Avatar Group suits inline density where the group is a single visual marker. The decision test: does each member need its own row of metadata (ListItem) or can the group be summarised as a single strip (Avatar Group)?

Avatar Group composes multiple Avatar instances into a single visual unit when a surface needs to communicate "this is a group" rather than "this is a person". Two layouts (stack-overlapped or grid-tiled), a bounded `max` count that triggers a +N overflow indicator, and an optional disclosure that reveals the collapsed members on click. The reference documents the group-role + accessible-name contract, the overflow-tile interactivity rule (button when it opens a popover, static text otherwise), and the divergence between libraries that ship a single AvatarGroup (MUI, Atlassian, HeroUI) and libraries that defer overflow to manual composition (Mantine, Chakra, PrimeReact).

Highlight
Fig 1.1 · Avatar Group · Designer view
Designer

Figma anatomy

Slot Figma type Hint
container frame Auto-layout frame; horizontal direction for stack variant, wrap-grid for grid variant; negative item-spacing for stack-overlap effect
avatar instance Avatar component instance; repeats per max property; z-index increments to layer correctly
overflow-indicator frame Avatar-shaped frame with "+N" centred text; visibility per "has overflow" property
overflow-popover frame Floating panel anchored below the overflow indicator; vertical list of member rows; popover-style elevation
Designer

Token usage per slot

container
spacing
  • gapspacing.tight
color
  • backgroundcolor.surface.bg
avatar
radius
  • cornerradius.full
overflow-indicator
radius
  • cornerradius.full
color
  • backgroundcolor.surface.sunken
  • foregroundcolor.text.muted
typography
  • sizetext.sm
  • weightweight.semibold
overflow-popover
radius
  • cornerradius.md
color
  • backgroundcolor.surface.raised
  • bordercolor.border.subtle
elevation
  • depthelevation.overlay
Both

Figma ↔ Code property map

FigmaKindCodeNotes
VariantEnumvariantMaps stack / grid layout variant.
SizeEnumsizeMaps xs / sm / md / lg / xl; mirrors Avatar size.
Overflow DirectionEnumoverflowDirectionend (default, last DOM avatar on top) or start (first DOM avatar on top).
InteractiveBooleaninteractiveWhen true, overflow indicator renders as `<button>` and opens a popover; when false, indicator is a labelled `<span>`.
MaxNumbermaxBound on visible avatar count; counts beyond render as +N indicator.
TotalNumbertotalOptional explicit total; when present, overrides children length for surplus computation.
AvatarsSlotavatarRepeatable slot for child Avatar instances.
Overflow PopoverSlotoverflow-popoverOptional disclosure surface; required when interactive is true.
Designer

Motion

TransitionDuration token
popoverOpenmotion.duration.fast
hoverShiftmotion.duration.fast
Easing
motion.easing.standard
Reduced motion
Instant (jump cut)
Designer

Responsive behaviour

BreakpointChange
breakpoint.smBelow this width, dense stacks step the avatar size down one tier (md → sm) and reduce the visible `max` by one or two so the strip fits without horizontal overflow. Grid variants reflow to fewer columns. Overflow-indicator always remains visible when total exceeds the reduced max.
breakpoint.mdAt and above this width, the canonical max applies and the size token returns to the explicit size. Grid variants return to their authored column count.
Both

Internationalisation

RTL · mirroring

Stack overlap direction follows `margin-inline-start` and the `overflowDirection` enum is logical — `end` flips from right-side-on-top (LTR) to left-side-on-top (RTL) automatically. Grid variant tile order also mirrors via writing-direction-aware grid auto-flow. Overflow indicator sits at the inline-end of the stack regardless of language — it follows the direction of growth, not a fixed visual corner.

Text expansion

Overflow indicator text "+5" stays compact across languages. The accessible-name suffix ("more members" → German "weitere Mitglieder" 60 % longer; Russian "еще участников" 80 % longer) expands invisibly to AT but never affects layout. Group `aria-label` ("Document collaborators") follows generic prose expansion — reserve no extra width because the label is not visible.

Both

Variants, properties, states

Variants

Structurally different versions of the component.

stack grid

Properties

The same component, parameterised.

PropertyType
size xs | sm | md | lg | xl
overflowDirection end | start
interactive boolean

States

Browser/user-driven (interactive) vs. app-driven (data).

KindStates
interactive
hoverfocus-visible
data
emptypartialoverflowingexpanded
Both

State transitions

FromToTrigger
overflowingexpandedUser activates overflow indicator (click, Enter, Space)
expandedoverflowingUser dismisses popover (Escape, outside click, indicator re-click)
Both

Figma↔Code mismatches

  1. 01
    Figma

    Avatars laid out with positive item-spacing (no overlap)

    Code

    Stack variant uses negative `margin-inline-start` to overlap avatars

    Consequence

    Designers ship the stack variant with non-overlapping avatars (positive gap); developers implement the canonical overlap with negative margins. The two surfaces look like different layouts even though they intend the same. Designers find the overlap "broken"; developers find the spec "underspecified".

    Correct

    Document the stack variant as overlapping by canonical contract (negative inline-start margin per avatar after the first; offset bound to size token). Grid variant uses positive gap and no overlap. Figma component variants enforce both layouts as first-class.

  2. 02
    Figma

    Overflow indicator drawn as static text "+5"

    Code

    Overflow indicator rendered as `<button>` with `aria-label`

    Consequence

    Designers ship "+5" as a text label; developers ship a button with `aria-label="5 more members"`. The visual element looks static but behaves as a focusable, clickable target. Designers do not draw the focus ring or hover state; developers ship them anyway, leading to design / implementation drift on focus affordance.

    Correct

    Document the overflow indicator as `<button>` whenever the group is interactive (opens a popover). Figma carries the button-state variants (default / hover / focused / active) so the focus ring is part of the design. Static overflow (no popover) is the rare case — document it separately as a labelled `<span>`.

  3. 03
    Figma

    Stack overlap direction hard-coded as left-overlaps-right

    Code

    Overlap direction follows `inset-inline-start` (logical, RTL-aware)

    Consequence

    Designers ship a fixed overlap direction (left avatar on top); developers use logical inline properties that flip under RTL. In RTL contexts the LTR Figma file ships with the reverse visual order, but the logical-property code agrees with the RTL reading direction. The two surfaces visually disagree.

    Correct

    Document the overlap direction as logical — `overflowDirection` `end` means the last DOM-order avatar sits on top in LTR and on the bottom in RTL. Figma shows both LTR and RTL frames; code uses logical properties uniformly.

  4. 04
    Figma

    Max count baked into Figma as a fixed-instance count

    Code

    `max` prop drives the runtime bound; total count comes from `total` prop or children length

    Consequence

    Designers ship a 5-avatar variant frame; developers compute visible count from `min(total, max)` and render the indicator from the surplus. The two surfaces decouple — designers may not draw the overflow-indicator state for every avatar count they author.

    Correct

    Document `max` and `total` as canonical properties; Figma illustrates the three data states (partial / overflowing / expanded) for at least one representative count. Code computes visible avatars and surplus from those props at render time.

Both

Contracts

Non-negotiable contracts

  1. APGWAI-ARIA role=group plus accessible-name pattern

    The container carries `role="group"` plus `aria-label` describing the group. Without either, SR users hear a sequence of individual avatar names without the "this is a group" semantic. The label should include the total member count when the overflow indicator does not surface it independently.

    Without the role and label, the group is a sighted-only composition. AT users encounter ambiguous avatar sequences — the membership boundary, the count, and the group's purpose all collapse into a flat list of names.

  2. Canon

    Counts beyond `max` collapse into a single overflow indicator with the literal surplus ("+N"). The indicator is non-optional whenever total count > `max`. Implementations that hide surplus avatars without the indicator communicate a smaller membership than reality.

    Without the indicator, users perceive the group as smaller than it is. The collapsed members lose representation; the membership count becomes lossy.

  3. APGAPG: Disclosure pattern

    The overflow indicator is `<button>` whenever it opens a popover (interactive group). It carries `aria-expanded` reflecting the popover state and `aria-controls` referencing the popover. Static groups (no popover) render the indicator as a labelled `<span>`. Implementations that ship a `<div>` with onClick lose keyboard activation, focus order, and disclosure semantics.

    Without the button semantic, keyboard users cannot reach the popover. AT users cannot perceive that the indicator is interactive — `aria-expanded` is the canonical signal for "this control toggles disclosed content".

Vocabulary drift

Material 3
Avatar
Material 3 spec defines Avatar but not AvatarGroup as a first-class component; library implementations (Material UI) ship AvatarGroup as a composition utility on top of Avatar. Same canonical contract, different documentation surface.
Atlassian
Avatar Group
Atlassian explicitly supports two layouts (stack or grid) as first-class variants — the rationale for the canonical variant axis. Most other libraries default to stack only.
Polaris
Avatar
Polaris ships Avatar but does not ship a canonical AvatarGroup — composition is left to the consumer. The canon documents this absence as an industry-divergence point, not a gap in the canon itself.
Carbon
User Avatar
Carbon ships User Avatar but no AvatarGroup — same pattern as Polaris. Consumers compose manually with custom layouts.
GOV.UK
GOV.UK Design System does not spec Avatar or AvatarGroup at all — government services rarely surface user-identity strips. The canon documents Avatar Group for the productivity-app context where the pattern is dominant.
Designer

Common mistakes

Blocker

#avatar-group-no-group-role

Container has no `role="group"` or `aria-label`

Problem

The container is a bare `<div>` with no role and no accessible name. SR users hear a sequence of individual avatar names without group context — "Alex Black image, Jamie Lee image, Sam Reyes image" — losing the "this is a collaborator strip" semantic entirely.

Fix

Set `role="group"` on the container plus `aria-label` describing the group ("Document collaborators (5)", "Team A members"). The label should include the total member count when the overflow indicator does not surface it. Avoid `role="list"` — list semantics are for sequential enumeration, not a bounded set.

Blocker

#avatar-group-overflow-no-aria-label

Overflow indicator shows "+N" with no accessible label

Problem

The indicator renders `<span>+5</span>` with no `aria-label`, no visually-hidden suffix, and no associated description. SR users hear "five" or "plus five" with no semantic — the count is ambiguous (more avatars? more members? more icons?).

Fix

When interactive, `<button aria-label="5 more members">+5</ button>` (or "+5 more"). When static, append a visually-hidden suffix — `<span>+5<span class="sr-only"> more members</span> </span>`. Never rely on the literal "+N" — the plus sign is visual shorthand without context for AT.

Major

#avatar-group-overflow-not-button-when-interactive

Overflow indicator is `<div>` or `<span>` but opens a popover

Problem

The indicator opens a member-list popover when clicked but ships as a non-button element (often a div with onClick). The element is not in the keyboard tab order, has no `aria-expanded`, and offers no Enter / Space activation. The popover is mouse-only.

Fix

Render the interactive overflow indicator as `<button>` with `aria-expanded` reflecting the popover state and `aria-controls` referencing the popover id. Static (no popover) overflow uses a `<span>`. The interactive boolean property toggles the rendered semantic — never ship a div that behaves like a button.

Major

#avatar-group-counts-beyond-max-silent-collapse

Counts beyond `max` collapse without the overflow indicator

Problem

The implementation hides avatars beyond `max` but does not render the +N indicator. Users see five collaborators in a ten-collaborator group with no signal that more exist. The group communicates a smaller membership than reality.

Fix

Whenever total count > `max`, render the overflow indicator with the literal surplus ("+N" where N = total - max). The indicator is non-optional in the overflowing state; only the partial state (total ≤ max) omits it.

Major

#avatar-group-popover-no-focus-trap

Popover opens but focus does not move into it

Problem

The disclosure popover opens on indicator click but keyboard focus stays on the indicator. Tab does not enter the popover; Escape does nothing. Keyboard users cannot navigate the member list — the popover is mouse-only despite the indicator being a button.

Fix

On open, move focus into the popover (first focusable element, or the popover container itself with `tabindex="-1"` for read-only lists). Escape closes the popover and returns focus to the indicator. Outside-click closes without focus restoration unless the click landed on another focusable element.

Accessibility hints
Slot Accessibility hint
container Carries `role="group"` plus `aria-label` describing the group ("Document collaborators (5)", "Team A members"). Without the label, SR users hear a sequence of individual avatar names without group context. The accessible name should include the total member count when the overflow indicator does not announce it.
avatar Each child Avatar carries its own accessible name (per the Avatar canon — image variant via `<img alt>`, initials / icon variants via `role="img"` + `aria-label`). The container's `role="group"` collects them; SR announces "group, Alex Black, Jamie Lee, Sam Reyes, +4 more".
overflow-indicator When interactive, `<button>` with `aria-label="N more members"` (or "+N more") plus `aria-expanded` reflecting the popover state. When static, `<span>` with the visible "+N" text and a visually-hidden "more members" suffix. Never rely on the literal "+N" alone — SR users without context cannot decode the plus sign.
overflow-popover The popover follows the disclosure pattern (APG): the overflow-indicator carries `aria-expanded` plus `aria-controls` referencing the popover; focus moves into the popover on open; Escape closes and returns focus to the indicator. When the popover is a list of selectable members, use `role="listbox"` with arrow-key navigation; when it is a read-only overview, use a generic container with a heading.