Avatar Group

Overlapping avatars where the hovered one rises, with a tooltip that glides from avatar to avatar.

<script setup lang="ts">
import {
  AvatarGroup,
  AvatarGroupTooltip,
  AvatarGroupTooltipArrow,
} from '@animate-ui/vue/primitives/avatar-group'
import { cn } from 'cn'
import { motion } from 'motion-v'

const PEOPLE = [
  { name: 'Skyleen', initials: 'SK', class: 'bg-rose-500' },
  { name: 'Shadcn', initials: 'CN', class: 'bg-amber-500' },
  { name: 'Adam Wathan', initials: 'AW', class: 'bg-emerald-500' },
  { name: 'Guillermo Rauch', initials: 'GR', class: 'bg-sky-500' },
  { name: 'Jhey', initials: 'JH', class: 'bg-violet-500' },
  { name: 'David Haz', initials: 'DH', class: 'bg-fuchsia-500' },
]
</script>

<template>
  <AvatarGroup class="h-12 -space-x-3" invert-overlap>
    <div
      v-for="person in PEOPLE"
      :key="person.name"
      role="img"
      :aria-label="person.name"
      tabindex="0"
      :class="cn(
        'flex size-12 items-center justify-center rounded-full border-3 border-background text-sm font-medium text-white outline-none select-none focus-visible:ring-2 focus-visible:ring-ring',
        person.class,
      )"
    >
      {{ person.initials }}
      <AvatarGroupTooltip class="rounded-md bg-foreground px-3 py-1.5 text-xs text-background">
        <AvatarGroupTooltipArrow class="size-2.5 fill-foreground" />
        <motion.p layout="preserve-aspect" class="whitespace-nowrap">
          {{ person.name }}
        </motion.p>
      </AvatarGroupTooltip>
    </div>
  </AvatarGroup>
</template>

Installation

npm install @animate-ui/vue motion-v
pnpm add @animate-ui/vue motion-v
yarn add @animate-ui/vue motion-v
bun add @animate-ui/vue motion-v

The tooltips are Animate UI's Tooltip, positioned with Floating UI, a peer dependency of this primitive:

npm install @floating-ui/vue
pnpm add @floating-ui/vue
yarn add @floating-ui/vue
bun add @floating-ui/vue

Usage

<script setup lang="ts">
import { AvatarGroup } from '@animate-ui/vue/primitives/avatar-group';

defineProps<{ people: { name: string; src: string }[] }>();
</script>

<template>
  <AvatarGroup class="h-12 -space-x-3" invert-overlap>
    <img
      v-for="person in people"
      :key="person.name"
      :src="person.src"
      :alt="person.name"
      class="size-12 rounded-full border-3 border-background"
    />
  </AvatarGroup>
</template>

Each child is an avatar. Put an AvatarGroupTooltip inside an avatar to give it a tooltip:

<div class="size-12 rounded-full border-3 border-background bg-muted">
  SK
  <AvatarGroupTooltip class="rounded-md bg-foreground px-3 py-1.5 text-xs text-background">
    <AvatarGroupTooltipArrow class="size-2.5 fill-foreground" />
    <p>Skyleen</p>
  </AvatarGroupTooltip>
</div>

Animation

  • The hovered (or pressed) avatar rises by translate on a bouncy spring (stiffness 300, damping 17): it overshoots by about 17% before it settles, and dips below its place the same way when it comes back down.
  • The tooltips share one popup (Tooltip): it opens at once (open-delay is 0) and glides from avatar to avatar on its spring (stiffness 400, damping 29), a little past the next avatar before it settles.
  • <AnimateUIProvider :tempo> paces the default springs.
  • Under reduced motion, the avatar rises at once and the tooltip only fades.

API Reference

AvatarGroup

Takes the TooltipProvider and Tooltip props, with other defaults.

PropTypeDefault
#default
slot-
invert-overlap?
booleanfalse
translate?
string | number'-30%'
transition?
Transition{ type: 'spring', stiffness: 300, damping: 17 }
tooltip-transition?
Transition{ type: 'spring', stiffness: 400, damping: 29 }
open-delay?
number0
close-delay?
number0
side?
"top" | "bottom" | "left" | "right""top"
side-offset?
number25
align?
"start" | "center" | "end""center"
align-offset?
number0
...props?
HTMLAttributes-

AvatarGroupTooltip

The TooltipContent props.

AvatarGroupTooltipArrow

The TooltipArrow props.

Credits

Built by Skyleen. The source code is available on GitHub.

Last updated: 10/23/2026