How to use Framer Motion with Emotion styled-components
May 12, 2020 / 3 min read
Last Updated: May 12, 2020First contact with Framer Motion
I recently took the time to check out Framer Motion, the current most popular React library for animating components. I've never been good at building smooth efficient transition, and even now I still have a lot to learn, but it's been surprisingly easy to transition some of the components powering this blog to use Framer Motion instead of CSS animations.
The projects I usually work on, however, rely heavily on styled-components built with Emotion, which allows me to write both animations and transitions with CSS syntax.
When converting these same animations to Framer Motion, I found myself wrapping my existing styled-components in a motion.div
component and migrate any animation code to this element. Little to say, it was tedious work, and I also wasn't satisfied with the resulting code:
1const StyledButton = styled('div')`2height: 48px;3margin: 0;4border: none;5cursor: pointer;6display: inline-flex;7justify-content: center;8align-items: center;9position: relative;10font-weight: 600;11outline: none;12padding: 0 30px;13border-radius: 4px;14background-color: #5184f9;15color: white;16min-width: 150px;17`;1819render(20<motion.button21whileHover={{ scale: 0.85 }}22transition={{ duration: 0.5 }}23style={{ background: 'transparent', border: 'none' }}24>25<StyledButton>Hello There</StyledButton>26</motion.button>27);
Cleaner implementation
Although the code above is working, I wanted to be able to declare a single component to hold both the style and the animation while keep using styled-components. My first instinct was to I try to wrap a motion.button
into Emotion's styled function as follows:
1const StyledButton = styled(motion.button)`2height: 48px;3margin: 0;4border: none;5cursor: pointer;6display: inline-flex;7justify-content: center;8align-items: center;9position: relative;10font-weight: 600;11outline: none;12padding: 0 30px;13border-radius: 4px;14background-color: #5184f9;15color: white;16min-width: 150px;17`;1819render(20<StyledButton whileHover={{ scale: 0.85 }} transition={{ duration: 0.5 }}>21Hello There22</StyledButton>23);
It worked! I now had a way to get my styled-components to use Framer Motion based animations and transition without requiring some extensive rewrite 🎉! The component showcased above is now able to take the props of a Framer Motion component, and I can tweak my animations and transitions directly from its props: no extra wrapping needed.
If you're still curious and want more examples of components I built this way, here's a list of some of the ones I rewrote on my gatsby-theme that powers this blog and my portfolio:
- the Button styled-component with a scale on hover animation.
- SearchBoxOverlay with blur animation: it blurs progressively the view while the search box appears to emphasize the focus on the search input and search results.
- SearchResults component with a slide down animation: the search result list may vary in size dependending on the length of the list of results for a given search query, this animation aims to smooth a bit the transition between two result lists.
I still have a lot to try with Framer Motion, I feel I barely scratched the surface and that I'm doing a couple of wrong things. Stay tuned for some future blog posts about my findings and what I learned using this library 🙌.
Liked this article? Share it with a friend on Bluesky or Twitter or support me to take on more ambitious projects to write about. Have a question, feedback or simply wish to contact me privately? Shoot me a DM and I'll do my best to get back to you.
Have a wonderful day.
– Maxime
Framer Motion x Emotion → animated styled-components