← Back to Blog

Building an Animated User Account Avatar Component

A deep dive into creating interactive dropdown menus with smooth spring animations, expandable sections, and accessibility features using Radix UI and Motion.

Eduardo CalvoEduardo Calvo
··1 min read

In this tutorial, we'll build the User Account Avatar component step by step. Scroll through to see how each feature is added - the component preview on the left will update as you progress.

Avatar Trigger

Start with a simple avatar button as the trigger element.

<button className="rounded-full border">  <img    src={user.avatar}    alt="Avatar"    className="rounded-full"    width={48}    height={48}  /></button>

Popover Container

Wrap the avatar with Radix UI's Popover for accessibility.

import { Popover, PopoverTrigger, PopoverContent }  from "@/components/ui/popover";<Popover>  <PopoverTrigger asChild>    {/* Avatar button */}  </PopoverTrigger>  <PopoverContent sideOffset={8}>    {/* Popover content */}  </PopoverContent></Popover>

Section Buttons

Add interactive section buttons with state management.

const [activeSection, setActiveSection] =  useState<string | null>(null);const handleClick = (section: string) => {  setActiveSection(    activeSection === section ? null : section  );};

Spring Animation

Add spring animations for smooth expansion effects.

<motion.div  initial={{ opacity: 0, height: 0 }}  animate={{ opacity: 1, height: "auto" }}  exit={{ opacity: 0, height: 0 }}  transition={{    type: "spring",    duration: 0.25,    bounce: 0  // No overshoot for professional feel  }}>

Why spring? Springs feel more natural than linear timing. Why bounce: 0? No overshoot keeps it professional.

Blur Effect

Add blur transition for a materializing effect.

initial={{  opacity: 0,  height: 0,  filter: "blur(10px)"}}animate={{  opacity: 1,  height: "auto",  filter: "blur(0px)"}}

The blur mimics how our eyes focus when something appears.

Progress Bars

Animate progress bars with spring physics.

<motion.div  initial={{ width: 0 }}  animate={{ width: `${progress}%` }}  transition={{    type: "spring",    stiffness: 300,    damping: 30,    duration: 0.4  }}/>

Higher stiffness = snappier. Longer duration lets users see the progress.

Complete

The final component with all features combined.

// The complete component includes:✓ Accessible Radix UI popover✓ Spring animations with no bounce✓ Blur transition effect✓ Animated progress bars✓ Reduced motion support✓ Keyboard accessibility

Try it! Click the avatar and explore the sections.

Live PreviewStep 1/7

Key Takeaways

After building this component, you've learned:

  1. Spring animations with bounce: 0-0.1 feel professional and natural
  2. Keep durations under 300ms for responsive UI
  3. Combine opacity + height + blur for polished expand/collapse effects
  4. Always support reduced motion with useReducedMotion() from Motion
  5. Use Radix primitives for built-in accessibility
  6. Test with keyboard and screen readers

Install the Component

Want to use this component in your project?

npx smoothui-cli add user-account-avatar

Check out the full documentation for all props and variations.

Share:

More Posts