Family Wallets

For a while now, I've been considering sharing the code for the interactions and prototypes I share on X. But there was always something holding me back. I'm not an engineer, and I often worried that my code might be too messy or that the solutions I came up with weren't perfect.


Funny enough, just as I was thinking about it, I stumbled upon this conversation and it encouraged me to share some of the code.

Jakub1.03 ETH
Savings25.08 ETH
Rainy Day0.04 ETH
Spending0 ETH
See the full code on CodeSandbox.
The Structure

As you can see in the preview above, the wallet component has three states: a default state when no wallet is expanded, an expanded state where the wallet changes size and components are added or swapped, and a collapsed state where the wallet is collapsed and components are removed.


To define specific content for each instance, I'm using props. For the animations, I rely on Framer Motion's shared layout animations to transition between different states of the component.


An important thing here is using a unique id for each component instance and setting the layoutId based on that id. This allows Framer Motion to know which components to animate between. If all components shared the same layoutId Framer Motion wouldn't be able to make the connection between them and the animations wouldn't work properly.

The Default State
Jakub1.03 ETH
The Expanded State
Copy Address
Jakub1.03 ETH
The Collapsed State
Jakub1.03 ETH
Translate X and Y

As a workaround to prevent icons from jittering in Safari on iOS, I've applied the translate-x-0 and translate-y-0 classes to each SVG component. Below, you can see the difference with and without these classes. This is a quick workaround I found for this issue. If you know of a better solution, please let me know!


By adding these classes you're essentially forcing the browser to use GPU acceleration for the element. This is because transforms (even with zero values) trigger hardware acceleration in most browsers.


It is important to note that is more of a hack rather than an actual solution. From what I've been able to find, Safari on iOS has a known issue with rendering SVG elements, especially during animations.

Translate classes not used.

Translate classes used.

Assembling the Animation

With the three wallet states defined, we can now assemble the animation. The code tracks which card is currently expanded and allows toggling between expanded and collapsed states when a card is clicked.


I also use the useRef hook to reference the div containing the wallet. This works with the useOnClickOutside hook to detect clicks outside the wallet component, resetting its state.


Lastly, a simple useEffect hook adds an event listener for the Escape key, which resets the component's state when the Escape key is pressed.

The final step is to put everything together. While this part of the code could probably be written more efficiently, I wanted to lay out all the different states so I'd have complete control over how everything fits together. This way, it'll be easier to tweak things if needed later on.


I'm wrapping the entire component in a MotionConfig to ensure that the transitions are consistent. Additionally, I'm using AnimatePresence to manage the exit animations for the components inside the wallets.

You can see the full code on CodeSandbox.


The interaction was inspired by Family. In case you have any questions you can reach me at j@kbo.sk or X (Twitter).