How to apply custom animation effect @keyframes in MaterialUI using makestyles()
Here is an example demonstrating the keyframes
syntax within makeStyles
:
import React from "react";import ReactDOM from "react-dom";import { makeStyles } from "@material-ui/core/styles";import Button from "@material-ui/core/Button";import clsx from "clsx";const useStyles = makeStyles(theme => ({ animatedItem: { animation: `$myEffect 3000ms ${theme.transitions.easing.easeInOut}` }, animatedItemExiting: { animation: `$myEffectExit 3000ms ${theme.transitions.easing.easeInOut}`, opacity: 0, transform: "translateY(-200%)" }, "@keyframes myEffect": { "0%": { opacity: 0, transform: "translateY(-200%)" }, "100%": { opacity: 1, transform: "translateY(0)" } }, "@keyframes myEffectExit": { "0%": { opacity: 1, transform: "translateY(0)" }, "100%": { opacity: 0, transform: "translateY(-200%)" } }}));function App() { const classes = useStyles(); const [exit, setExit] = React.useState(false); return ( <> <div className={clsx(classes.animatedItem, { [classes.animatedItemExiting]: exit })} > <h1>Hello CodeSandbox</h1> <h2>Start editing to see some magic happen!</h2> <Button onClick={() => setExit(true)}>Click to exit</Button> </div> {exit && <Button onClick={() => setExit(false)}>Click to enter</Button>} </> );}const rootElement = document.getElementById("root");ReactDOM.render(<App />, rootElement);
Documentation: https://cssinjs.org/jss-syntax/?v=v10.0.0#keyframes-animation
For those who have started using Material-UI v5 and want to know how to do this using Emotion rather than makeStyles
, below is an example of one way to do the equivalent styles using Emotion.
/** @jsxImportSource @emotion/react */import React from "react";import ReactDOM from "react-dom";import { css, keyframes } from "@emotion/react";import { useTheme } from "@material-ui/core/styles";import Button from "@material-ui/core/Button";const myEffect = keyframes` 0% { opacity: 0; transform: translateY(-200%); } 100% { opacity: 1; transform: translateY(0); }`;const myEffectExit = keyframes` 0% { opacity: 1; transform: translateY(0); } 100% { opacity: 0; transform: translateY(-200%); }`;function App() { const theme = useTheme(); const animatedItem = css` animation: ${myEffect} 3000ms ${theme.transitions.easing.easeInOut}; `; const animatedItemExiting = css` animation: ${myEffectExit} 3000ms ${theme.transitions.easing.easeInOut}; opacity: 0; transform: translateY(-200%); `; const [exit, setExit] = React.useState(false); return ( <> <div css={exit ? animatedItemExiting : animatedItem}> <h1>Hello CodeSandbox</h1> <h2>Start editing to see some magic happen!</h2> <Button onClick={() => setExit(true)}>Click to exit</Button> </div> {exit && <Button onClick={() => setExit(false)}>Click to enter</Button>} </> );}const rootElement = document.getElementById("root");ReactDOM.render(<App />, rootElement);
Emotion keyframes documentation: https://emotion.sh/docs/keyframes
Just some notes on top of @Ryan's answer. If you define the keyframe
using makeStyles
. Remember to prefix the animation name with $
. I missed this small detail the first time and my code didn't work, in the example below
const useStyles = makeStyles({ "@keyframes fadeIn": { "0%": { opacity: 0, transform: "translateY(5rem)" }, "100%": { opacity: 1, transform: "translateY(0)" } }, selector: { animation: "$fadeIn .2s ease-in-out" }});
Instead of
animation: "fadeIn .2s ease-in-out"
It should be
animation: "$fadeIn .2s ease-in-out"
But if you define the keyframe
in global scope. The prefix is unnecessary here
const useStyles = makeStyles({ "@global": { "@keyframes fadeIn": { "0%": { opacity: 0, transform: "translateY(5rem)" }, "100%": { opacity: 1, transform: "translateY(0)" } } }, selector: { animation: "fadeIn .2s ease-in-out" // --> this works }});
Follow this issue on github for more discussion about this.