Skip to content

Avatar Stack

Show a group of people as overlapping avatars, with presence and an expandable list.

import { AvatarStack, AvatarStackUser } from '@youj/react'

Installation & usage

npm i @youj/react

For an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.

Use an avatar stack to show who is in a document, a project or a call, when the faces matter more than the details. It shows the first max people and puts everyone else behind a "+N" button that opens the full list with each person's role and status. For a single person, use an Avatar. For a list people manage (roles, removal), use a table or a list, not a stack.

import { AvatarStack, type AvatarStackUser } from '@youj/react'

const people: AvatarStackUser[] = [
  { id: 'mira', name: 'Mira Chen', src: '/avatars/mira.jpg', presence: 'online', description: 'Design lead' },
  { id: 'jonas', name: 'Jonas Weber', presence: 'away' },
  // …
]

export function Collaborators() {
  return <AvatarStack users={people} label="Collaborators" />
}

Each person needs an id and a name. Without a src, the avatar shows their initials. presence adds a status dot (online, away, busy or offline), and description is the second line in the full list. label names the group ("Collaborators: Mira Chen, Jonas Weber and 5 others") and heads the list.

On a card, set the rings that cut the overlaps out to the card's color, as the demo does: *:data-[slot=avatar]:ring-surface.

Reference

Propsusers, max, size… (4)

Props

AvatarStack props
PropType
usersRequiredreadonly AvatarStackUser[]–
maxnumber

Avatars shown before "+N".

default 4

4
size'sm' | 'default' | 'lg'

default 'default'

'default'
labelstring

What the people are, for the group's name and the list heading.

default "People"

"People"
Other props pass through: extends ComponentProps<'div'>.
MotionFan out, lift, presence dot… · reduced motion

Motion

Motion tokens
MomentTokens
Fan outhovering the stack spreads each avatar 3px per position towards the inline end (translate)
duration.fastease.standard

140ms · cubic-bezier(0.2, 0, 0, 1)

140mscubic-bezier(0.2, 0, 0, 1)
Liftthe avatar under the pointer rises 2px above its neighbors
duration.fastease.standard

140ms · cubic-bezier(0.2, 0, 0, 1)

140mscubic-bezier(0.2, 0, 0, 1)
Presence dotpops in from scale 0 when a status changes
duration.baseease.enter

220ms · cubic-bezier(0.16, 1, 0.3, 1)

220mscubic-bezier(0.16, 1, 0.3, 1)
Name tooltipdrifts off the avatar (yj-tooltip), after a 200ms hover delay
no token

Full listscales from "+N" as it fades in (yj-pop)
no token

Reduced motion

No fan and no lift; status dots appear without the pop.

Only transforms move, so the stack never reflows the line it sits in.

Reduced motion

The stack doesn't fan out on hover, the hovered avatar doesn't lift and status dots appear in place. Tooltips and the list still open, with the overlay presets' reduced behavior.

AccessibilityKeyboard, announcements

Accessibility

  • The stack is a group named with everyone in it: the first two names and a count of the rest.
  • Each avatar shows the person's name and status in a tooltip on hover. Avatars aren't in the tab order, so keyboard and screen reader users get the names from the group's label and the "+N" list.
  • "+N" is a button named "Show all 7 collaborators". It opens the list in a Popover, where each status is written out, not only shown as a color.
  • Presence dots are decorative; the status text is in the tooltip and the list.