ATOM
Components (registry)Indicators

AvatarGroup

Faces stack with a +N overflow when the list grows. Team members and multi-assignee fields.

Preview

Sizes: xssml (default: s)

Editorial

<!-- F12c editorial — non-derivable only. Review: Karen. -->

## Ejemplos

Team row with overflow:

```tsx import { AvatarGroup } from '@/components/atoms/AvatarGroup'; import { Avatar } from '@/components/atoms/Avatar';

<AvatarGroup size="s" max={3}> <Avatar type="image" src="/u/1.jpg" alt="A" /> <Avatar type="image" src="/u/2.jpg" alt="B" /> <Avatar type="image" src="/u/3.jpg" alt="C" /> <Avatar type="image" src="/u/4.jpg" alt="D" /> </AvatarGroup> ```

## Accesibilidad

- Each child `Avatar` still needs its own name (`alt` / `aria-label`). - Overflow “+N” is visual — provide a textual count nearby when the full roster matters (e.g. “4 assignees”).

### Correcto

- Cada Avatar hijo debe tener alt con el nombre del usuario - Count badge (+N) es decorativo — complementar con texto como 'y 3 mas' fuera del grupo - Z-index descendente: primer avatar = mas importante visualmente (encima de los demas)

### Evitar

- No usar max sin indicar cuantos usuarios hay en total — '+3' sin contexto no es util - No mezclar sizes distintos entre AvatarGroup y sus Avatar hijos - No usar mas de 10 avatares visibles — el z-index stack solo cubre 10 niveles

## Cuándo no usar

- Single person → `Avatar`. - Editable assignee pickers that need full names listed → list/`Item` rows, not only a face stack.

## Criterio de uso

- Usa el grupo para resumir participantes cuando el espacio es limitado y el detalle completo puede abrirse en otro contexto. - Elige `max` según el ancho real de la superficie; un `+N` debe representar a todas las personas ocultas, no sólo a las que no cupieron en la primera fila. - Mantén tamaño y forma consistentes con los Avatars vecinos y con la densidad del producto.

## Gotchas

- El overflow visual necesita resumen textual accesible, especialmente si la lista representa responsables o permisos. - Sólo acepta Avatars como hijos; no mezcles texto o controles sin un patrón de lista explícito. - **Nota**: CSS requiere Avatar standalone CSS como prerequisito. AvatarGroup solo agrega overlap, z-index stack y count badge.

Uso

import { Avatar, AvatarGroup } from '@/components/atoms/Avatar';

<AvatarGroup size="s" max={3}>
  <Avatar type="initials" initials="AL" alt="Ada" />
  <Avatar type="initials" initials="GR" alt="Grace" />
  <Avatar type="initials" initials="KT" alt="Katherine" />
  <Avatar type="initials" initials="XX" alt="Extra" />
</AvatarGroup>

Props

PropTipoDefaultRango / opcionesWhatHow
sizeselects`xs`, `s`, `m`, `l`Size applied to all children avatars.s in lists; m in page headers. Keep consistent with surrounding density. Default: s.
shapeselectcircle`circle`, `square`Shape applied to children.Match Avatar shape in the same product surface. Default: circle.
maxnumber1–12 step 1 countMax faces before +N overflow.3–5 in cards; higher only when space is guaranteed.

Gotchas

  • react

    Children must be Avatar components; max trims visually and should be reflected in accessible summary text (+N people).

Anatomía CSS

<div class="avatar-group">
  <span class="avatar-group__count"></span>
</div>
ClasePropósito
avatar-grouproot
avatar-group--lmodifier
avatar-group--mmodifier
avatar-group--smodifier
avatar-group--squaremodifier
avatar-group--xsmodifier
avatar-group__countelement

Tokens resueltos

Valores finales tras seguir la cadena de tokens. Derivados del source: si un token cambia, esta tabla cambia sola.

VariantePropValorToken
allbg#f5f5f5muted
allfg#525252muted.foreground

CSS mínimo funcional

Autocontenido: sin imports ni tokens. Para previews y prototipos — en producción se consume el CSS del DS (@atom-uikit/css/components.css</code>, <code>@atom-uikit/tokens/tokens.css).

/* -------------------------------------------------------------------------
   Avatar Group

   Stacked row of avatars with negative overlap.
   Wraps standard Avatar components.

   Sizes:   xs, s, m, l (match Avatar sizes)
   Parts:   .avatar-group, .avatar-group__count
   ------------------------------------------------------------------------- */

.avatar-group {
  display: inline-flex;
  align-items: center;
}

/* Negative overlap per size */

.avatar-group--xs > .avatar { margin-left: -0.375rem; }
.avatar-group--s  > .avatar { margin-left: -0.5rem; }
.avatar-group--m  > .avatar { margin-left: -0.625rem; }
.avatar-group--l  > .avatar { margin-left: -0.75rem; }

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

/* Z-index: first child on top, descending */

.avatar-group > .avatar,
.avatar-group > .avatar-group__count {
  position: relative;
}

.avatar-group > :nth-child(1)  { z-index: 10; }
.avatar-group > :nth-child(2)  { z-index: 9; }
.avatar-group > :nth-child(3)  { z-index: 8; }
.avatar-group > :nth-child(4)  { z-index: 7; }
.avatar-group > :nth-child(5)  { z-index: 6; }
.avatar-group > :nth-child(6)  { z-index: 5; }
.avatar-group > :nth-child(7)  { z-index: 4; }
.avatar-group > :nth-child(8)  { z-index: 3; }
.avatar-group > :nth-child(9)  { z-index: 2; }
.avatar-group > :nth-child(10) { z-index: 1; }

/* Ring to separate overlapping avatars */

.avatar-group > .avatar {
  box-shadow: 0 0 0 2px #fafafa;
}

/* Count badge (+3 more) */

.avatar-group__count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 9999px;
  background-color: #f5f5f5;
  color: #525252;
  font-family: 'inter tight', -apple-system, blinkmacsystemfont, 'segoe ui', roboto, helvetica, arial, sans-serif, ui-sans-serif, system-ui, sans-serif;
  font-weight: 500;
  line-height: 1;
  box-shadow: 0 0 0 2px #fafafa;
}

/* Count badge inherits square shape */
.avatar-group--square .avatar-group__count { border-radius: 8px; }
.avatar-group--square.avatar-group--m .avatar-group__count { border-radius: 12px; }
.avatar-group--square.avatar-group--l .avatar-group__count { border-radius: 16px; }

.avatar-group--xs .avatar-group__count { width: 1.5rem; height: 1.5rem; font-size: 10.24px; margin-left: -0.375rem; }
.avatar-group--s  .avatar-group__count { width: 2rem; height: 2rem; font-size: 10.24px; margin-left: -0.5rem; }
.avatar-group--m  .avatar-group__count { width: 2.5rem; height: 2.5rem; font-size: 12.8px; margin-left: -0.625rem; }
.avatar-group--l  .avatar-group__count { width: 3rem; height: 3rem; font-size: 12.8px; margin-left: -0.75rem; }

Codigo fuente

components-react
components/atoms/AvatarGroup.tsx
import { type ReactNode } from 'react';

function cn(...classes: (string | false | undefined | null)[]) {
  return classes.filter(Boolean).join(' ');
}

type AvatarGroupSize = 'xs' | 's' | 'm' | 'l';

type AvatarGroupShape = 'circle' | 'square';

export type AvatarGroupProps = {
  size?: AvatarGroupSize;
  shape?: AvatarGroupShape;
  max?: number;
  children: ReactNode;
  className?: string;
};

export function AvatarGroup({ size = 's', shape = 'circle', max, children, className }: AvatarGroupProps) {
  const items = Array.isArray(children) ? children : [children];
  const visible = max ? items.slice(0, max) : items;
  const remaining = max ? items.length - max : 0;

  return (
    <div className={cn('avatar-group', `avatar-group--${size}`, shape === 'square' && 'avatar-group--square', className)}>
      {visible}
      {remaining > 0 && (
        <span className="avatar-group__count">+{remaining}</span>
      )}
    </div>
  );
}

Webflow

Webflowavatar-group

Pega en el Designer como application/json, luego convierte a Component (Atom / AvatarGroup) y publica. Formato interno no documentado de Webflow — regenerable, no dependencia de runtime.

Setup del sitio (una vez)

Custom Code → Head:

<link rel="stylesheet" href="https://atom-web-ds.vercel.app/v1/tokens.css">
<link rel="stylesheet" href="https://atom-web-ds.vercel.app/v1/components.css">

Unsupported (no silencioso)

  • selector on .avatar-group--xs > .avatarcompound/descendant selector — moved to head Custom Code (Designer styles are single-class)
  • selector on .avatar-group--s > .avatarcompound/descendant selector — moved to head Custom Code (Designer styles are single-class)
  • selector on .avatar-group--m > .avatarcompound/descendant selector — moved to head Custom Code (Designer styles are single-class)
  • selector on .avatar-group--l > .avatarcompound/descendant selector — moved to head Custom Code (Designer styles are single-class)
  • selector on .avatar-group > .avatar:first-childcompound/descendant selector — moved to head Custom Code (Designer styles are single-class)
  • selector on .avatar-group > .avatar, .avatar-group > .avatar-group__countcompound/descendant selector — moved to head Custom Code (Designer styles are single-class)
  • selector on .avatar-group > :nth-child(1)compound/descendant selector — moved to head Custom Code (Designer styles are single-class)
  • selector on .avatar-group > :nth-child(2)compound/descendant selector — moved to head Custom Code (Designer styles are single-class)

Tras pegar: Create component → nombre Atom / AvatarGroup → Publish.

Componentes relacionados

On this page

Detalles

Publicado14 de mayo de 2026
Categoriaindicators
Lectura...
Visitas...
Ayuda?Slack

Componente

AvatarGroup

Source

components-react / cssDisponible via MCP: atom_uikit_source("avatar-group")
Abrir en Storybook