I have learnt to use animation in CSS using @keyframe
. I however want to write my custom animation code to my React project (using MUI). My challenge is how I can write the Javascript code to custom my animations using the makeStyle()
in MUI.
I want to be able to custom the transitions processes in percentages
this time around in MUI. I need to be able to write codes like this in makeStyle()
but I don't seem to know how to.
@keyframes myEffect {
0%{
opacity:0;
transform: translateY(-200%);
}
100% {
opacity:1;
transform: translateY(0);
}
}
A keyframe can be a “step” If we set up a keyframe animation to change the background color of an element to change from orange to black (because orange is the new black, after all) on hover over five seconds, it will do exactly that. It will divide that change up over time and make the transition.
To use keyframes, create a @keyframes rule with a name that is then used by the animation-name property to match an animation to its keyframe declaration.
And just like in After Effects, keyframes are a fundamental piece of animating in Animate. Animation in Animate uses tweened frame spans, which means the frames that span the duration between two keyframes contain an animated element.
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 "@mui/material/styles";
import Button from "@mui/material/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
V5
In v5, you can use the keyframes
function (which is re-exported from emotion by default) to generate the stylesheet for keyframe:
import { styled } from '@mui/material/styles';
import { keyframes } from '@mui/system';
const spin = keyframes`
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
`;
const RotatedBox = styled("div")({
backgroundColor: "pink",
width: 30,
height: 30,
animation: `${spin} 1s infinite ease`
});
Because both styled
/sx
prop use emotion internally, you can pass the same style object to the sx
prop:
<Box
sx={{
backgroundColor: "pink",
width: 30,
height: 30,
animation: `${spin} 1s infinite ease`
}}
/>
V4
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With