How to apply custom animation effect @keyframes in MUI?
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
MUI 5 - keyframe animation using styled API not working
Emotion's keyframe
is a tag function. It accepts a template string as the first argument and returns the keyframe data. What you defined in your code is a function that just returns another function without doing anything:
const getAnimation = () => keyframes`
0 % { transform: translate(1px, 1px) rotate(0deg) },
...
100% { transform: translate(1px, -2px) rotate(-1deg); }
`;
You're supposed to change the code to this:
const myKeyframe = keyframes`
0 % { transform: translate(1px, 1px) rotate(0deg) },
...
100% { transform: translate(1px, -2px) rotate(-1deg); }
`;
Usage
const StyledButton = styled((props) => <Button {...props} />)(({ theme }) => ({
":hover": {
backgroundColor: "#2699FB",
// I also fixed the animation sub-property order of yours
// See: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations#configuring_the_animation
animation: `${myKeyframe} 1s infinite ease`
},
backgroundColor: "#2699FB",
color: "#FFFFFF"
}));
Live Demo
Add shake animation when the character limit react 100
import React, { useState, useContext } from "react";
import "./styles.css";
import { makeStyles } from "@mui/styles";
import { TextField } from "@mui/material";
const useStyles = makeStyles(() => ({
shake: {
animation: "$description 15s",
animationIterationCount: "1"
},
"@keyframes description": {
"0%": { opacity: 0, transform: "translateY(0)" },
"15%": { transform: "translateY(-4px, 0)" },
"30%": { transform: "translateY(6px, 0)" },
"45%": { transform: "translateY(-4px, 0)" },
"60%": { transform: "translateY(6px, 0)" },
"100%": { opacity: 1, transform: "translateY(0)" }
}
}));
export default function App() {
const classes = useStyles();
console.log(classes.shake);
const CHARACTER_LIMIT = 100;
const [isShake, setShake] = useState(false);
const [getStringDescription, setStringDescription] = useState({
length: 0,
value: ""
});
const onHandleChangeInputDescription = (field, value) => {
if (value.target.value.length === 100) {
setShake(true);
}
setStringDescription({
length: value.target.value.length,
value: value.target.value
});
};
return (
<div className="App">
<TextField
label="Description"
inputProps={{
maxLength: CHARACTER_LIMIT
}}
values={getStringDescription.name}
onChange={(value) =>
onHandleChangeInputDescription("description", value)
}
helperText={`${getStringDescription.length}/${CHARACTER_LIMIT}`}
sx={{
"& .MuiInputBase-input.MuiInputBase-inputMultiline": {
height: "100px !important"
},
"& .MuiTextField-root > .MuiOutlinedInput-root": {
padding: "8.5px 14px"
}
}}
id="description"
className={isShake ? classes.shake : null}
/>
</div>
);
}
React MUI focusVisible ripple animation on hover
One of the Button props is touchRippleRef
, which exposes a pulsate()
function. I wrapped the Button
component, and got the pulsing-ripple-animation on hover working:
function LinkButton(props: ButtonProps) {
const touchRippleRef = useRef<TouchRippleActions>(null)
return <Button
{...props}
touchRippleRef={touchRippleRef}
onMouseEnter={() => touchRippleRef.current?.pulsate()}
onMouseLeave={() => touchRippleRef.current?.stop()}
/>
}
Works like a charm.
Related Topics
CSS - First Child Without Certain Class
Make Scrollbars Only Visible When a Div Is Hovered Over
Horizontal Masonry Layout with Flexbox CSS Only
Table Border Color in CSS with Border Collapse
How to Make Card-Columns Order Horizontally
CSS Variables Defaults: Set If Not Already Set
Must Bootstrap Container Elements Include Row Elements
:Nth-Letter Pseudo-Element Is Not Working
How to Target Microsoft Edge with CSS
Css: Constrain a Table with Long Cell Contents to Page Width
CSS Layout, Use CSS to Reorder Divs
Where Do the Lost Pixels Go in a Percent CSS Layout
CSS Background Image Url Failing to Load
How to Change Md-Input-Container Placeholder Color Using CSS in Angular Material