Start with creating motion variants of your UI components using Framer Motion's motion() function.
const MotionAvatar = motion(Avatar);
This allows us to use all the motion capabilities while maintaining the original component's styling and functionality.
The magic happens with Framer Motion's layout animations. Each avatar gets a unique layoutId that connects its collapsed and expanded states:
// In collapsed state
<MotionAvatar
  layoutId={`vci-avatar-${user.name}`}
  className="ring-2 ring-background border-2 border-background cursor-pointer"
  layout
>
  <AvatarImage src={user.avatar} alt={user.name} />
  <AvatarFallback>
    {user.name.split(" ").map((n) => n[0]).join("")}
  </AvatarFallback>
</MotionAvatar>
// In expanded state  
<MotionAvatar layoutId={`vci-avatar-${user.name}`} layout>
  <AvatarImage src={user.avatar} alt={user.name} />
  <AvatarFallback>
    {user.name.slice(0, 2).toUpperCase()}
  </AvatarFallback>
</MotionAvatar>
When Framer Motion sees the same layoutId in different positions, it automatically animates the element between those positions.
The component includes several key features:
User Overflow Handling: When there are more users than can be displayed in the collapsed state, it shows a count:
const slice = 5;
const visibleUsers = users.slice(0, slice);
const hideUserCounted = users.length - slice;
{hideUserCounted > 0 && (
  <MotionAvatar layout>
    <AvatarFallback>+{hideUserCounted}</AvatarFallback>
  </MotionAvatar>
)}
Different Avatar Fallback Logic: The collapsed and expanded states show different fallback text formats - initials vs. first two characters:
// Collapsed: Shows initials (e.g., "CN" for "Charlotte Nova")
<AvatarFallback>
  {user.name.split(" ").map((n) => n[0]).join("")}
</AvatarFallback>
// Expanded: Shows first two characters (e.g., "CH" for "Charlotte Nova")  
<AvatarFallback>
  {user.name.slice(0, 2).toUpperCase()}
</AvatarFallback>
The component uses AnimatePresence to handle the transition between collapsed and expanded states:
<AnimatePresence mode="wait">
  {!open && (
    <motion.div
      className={cn(
        "w-fit p-2 rounded-full border border-border",
        "flex items-center",
        "flex -space-x-2 shadow-sm bg-background"
      )}
      role="button"
      onClick={() => setOpen(!open)}
    >
      {/* Collapsed state content */}
    </motion.div>
  )}
  {open && (
    <motion.section className="w-[300px] min-h-[300px] rounded-2xl bg-background border border-border">
      {/* Expanded state content */}
    </motion.section>
  )}
</AnimatePresence>
The layout prop tells Framer Motion to animate any layout changes automatically:
<motion.div layout>
  {/* Content that might change size/position */}
</motion.div>
This handles things like text reflow, size changes, and position adjustments without any manual animation code.
Framer Motion's layout animations use the FLIP technique (First, Last, Invert, Play):
- First: Record the initial position/size
 - Last: Record the final position/size
 - Invert: Apply a transform to make it look like it's still in the first position
 - Play: Animate back to the natural position
 
This creates incredibly smooth transitions because the browser's layout engine handles the heavy lifting.
When transitioning from the horizontal stack to the grid layout, multiple things happen simultaneously:
- Position changes: Avatars move to new grid positions
 - Size changes: Container expands from compact to full width
 - Layout changes: Flex to grid layout transformation
 - Content changes: Names appear, additional UI elements fade in
 
Framer Motion coordinates all these changes to feel like a single, cohesive animation.
Motion automatically promotes animated elements to their own compositor layer, avoiding expensive repaints and ensuring smooth 60fps animations.
// GPU-accelerated transforms happen automatically
<motion.div layout>
  <MotionAvatar layoutId={`vci-avatar-${user.name}`} layout>
    <AvatarImage src={user.avatar} alt={user.name} />
    <AvatarFallback>
      {user.name.slice(0, 2).toUpperCase()}
    </AvatarFallback>
  </MotionAvatar>
</motion.div>
Framer Motion also automatically respects the user's prefers-reduced-motion setting, disabling animations for users who prefer less motion.
Finally, we get a buttery-smooth interface that feels magical to use, while being built with simple, maintainable code.