Avatar-group

Default

A B C

With overflow

A B C +5

Tight

D E F G

Loose

H I J

  
/*
 * Avatar-group — element (display)
 *
 * Overlapping stack of avatars. Used to show participants, owners, or
 * any collection of people associated with a thing. CSS-only.
 *
 *   <div class="avatar-group">
 *     <span class="avatar">A</span>
 *     <span class="avatar">B</span>
 *     <span class="avatar">C</span>
 *     <span class="avatar -overflow">+5</span>
 *   </div>
 */

@layer malevich.components {
  .avatar-group {
    --avatar-group-overlap: calc(var(--size-control-m) * 0.4);

    display: inline-flex;
    align-items: center;
    isolation: isolate;
  }

  .avatar-group > .avatar {
    border: var(--border-width-emphasis) solid var(--color-surface-canvas);
    position: relative;
    margin-inline-start: calc(-1 * var(--avatar-group-overlap));
  }

  .avatar-group > .avatar:first-child {
    margin-inline-start: 0;
  }

  /* Later siblings stack visually below the earlier ones — hover the
   * earlier ones to read them clearly. Z-index decreases along the
   * row so the first avatar sits on top.
   */
  .avatar-group > .avatar:nth-child(1) { z-index: 6; }
  .avatar-group > .avatar:nth-child(2) { z-index: 5; }
  .avatar-group > .avatar:nth-child(3) { z-index: 4; }
  .avatar-group > .avatar:nth-child(4) { z-index: 3; }
  .avatar-group > .avatar:nth-child(5) { z-index: 2; }
  .avatar-group > .avatar:nth-child(6) { z-index: 1; }

  /* Overflow indicator: e.g. "+5" appended after visible avatars */
  .avatar-group > .avatar.-overflow {
    background-color: var(--color-surface-raised);
    color: var(--color-ink-regular);
  }

  /* Variants */

  .avatar-group.-tight {
    --avatar-group-overlap: calc(var(--size-control-m) * 0.6);
  }

  .avatar-group.-loose {
    --avatar-group-overlap: calc(var(--size-control-m) * 0.15);
  }

  /* When sitting on a non-canvas surface, expose the border tone via
   * a custom property the author can override. Defaults to canvas.
   */
  .avatar-group.-on-raised > .avatar {
    border-color: var(--color-surface-raised);
  }
}
This component is pure CSS — no JavaScript required.
# Avatar-Group — AGENTS.md

> Auto-generated from `avatar-group.docs.md` + the modifier applicability matrix.
> Edit those source files; this file regenerates on build.

## Identity

- **Component:** `avatar-group`
- **Layer:** elements
- **Status:** stable
- **Last updated:** 2026-05-19

## Summary

- Showing 2-6 people associated with a thing.

## Variants

| Variant   | Class                        | Use for                                |
|-----------|------------------------------|----------------------------------------|
| Default   | `.avatar-group`              | Standard overlap                       |
| Tight     | `.avatar-group.-tight`       | More overlap (denser)                  |
| Loose     | `.avatar-group.-loose`       | Less overlap (more visible)            |
| On raised | `.avatar-group.-on-raised`   | Border tone matches raised surface     |

## Modifier applicability

Per ADR-0007. Modifiers attach via `data-{category}="value"` attributes.

| Category | Accepts |
|---|---|
| `background` | — |
| `surface` | — |
| `effect` | — |
| `shader` | — |
| `rhythm` | `compact`, `regular` |
| `motion` | — |
| `behavior` | — |

## Anatomy

```html
<div class="avatar-group">
  <span class="avatar">A</span>
  <span class="avatar">B</span>
  <span class="avatar">C</span>
  <span class="avatar -overflow">+5</span>
</div>

<!-- With images -->
<div class="avatar-group -tight">
  <img class="avatar" src="alex.jpg" alt="Alex" />
  <img class="avatar" src="bo.jpg" alt="Bo" />
  <img class="avatar" src="chris.jpg" alt="Chris" />
</div>
```

The component uses CSS to:
- Negative margin each avatar onto the previous one
- Add a border in the surface color so each avatar reads as separate
- Stack first avatar on top via z-index

## Tokens consumed

- `--size-control-m` — base avatar size for overlap math
- `--color-surface-canvas` — border (default)
- `--color-surface-raised` — border (on-raised variant) + overflow bg
- `--color-ink-regular` — overflow text
- `--border-width-emphasis` — border thickness

## Accessibility contract

The group itself is decorative — there is no list semantics. If the
group represents a meaningful collection (e.g. assignees to a task),
wrap it in a labeled container:

```html
<div aria-label="Assigned to 8 people">
  <div class="avatar-group">
    <span class="avatar" aria-label="Alex">A</span>
    <span class="avatar" aria-label="Bo">B</span>
    <span class="avatar -overflow" aria-label="and 6 more">+6</span>
  </div>
</div>
```

The individual avatar accessibility is the consumer's choice — for an
image avatar, `<img alt="">` is correct; for an initials avatar, an
`aria-label` carries the name.

## Guidance

### Do

- Limit visible avatars to 4-6 + an overflow indicator.
- Order most-important first (they sit on top).
- Match the border color to the surface the group sits on.

### Don't

- Don't put a list of 20 avatars in a group. Use a different display.
- Don't mix avatar sizes within one group — overlap math assumes
  uniform size.