Passing props in makeStyles keyframe animations

Viewed 1900

How to pass props fill value to makeStyles' keyframe? Do I have to specify initial states to pass the prop?

It works for the color but does not work for fillvalue.

---Child component

const useStyles = makeStyles({
      progress: {
            animation: '$load 3s normal forwards',
            background: props => props.color,
            width: '0',
            },

      "@keyframes load": {
            "0%": { width: "0" },
            "100%": { width: props => props.fillvalue}
            }
});

export default function ProgressBar(props) {
      const propsStyle = {color: props.color, fillvalue: props.fillvalue}
      const classes = useStyles(propsStyle)
      
      return(
            <div>
                  <div className={classes.progress}>
                  </div>
            </div>
      );
}


---Parent

function App() {
  return (
    <div>
      <ProgressBar color="#000" fillvalue = "60%"/>
    </div>
  );
}

2 Answers

The answer to this is - you can't (at least for now). This is a bug as of this writing (MUI latest release is v4.11.0 as of this writing) and is acknowledged by one of the MUI contributors. You can track its progress at this issue: https://github.com/mui-org/material-ui/issues/21011

You are going to have to find other means of passing those props without the use of keyframes

const useStyles = makeStyles({
  progress: {
    height: "10px",
    background: (props) => props.color,
    width: (props) => props.fillvalue,
    transition: "width 3s"
  }
});

function ProgressBar(props) {
  const propsStyle = { color: props.color, fillvalue: props.fillvalue };
  const classes = useStyles(propsStyle);

  return (
    <div>
      <div className={classes.progress}></div>
    </div>
  );
}

function App() {
  const [fill, setFill] = React.useState("0%");

  return (
    <div>
      <button onClick={() => setFill("0%")}>0%</button>
      <button onClick={() => setFill("60%")}>60%</button>
      <ProgressBar color="#aaa" fillvalue={fill} />
    </div>
  );
}

ReactDOM.render(<App/>,document.getElementById("root"));
<body>
  <div id="root"></div>

  <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
  <script src="https://unpkg.com/@material-ui/core@latest/umd/material-ui.development.js"></script>

  <script type="text/babel">
    const { makeStyles } = MaterialUI;
  </script>
</body>

I see that there is no shorter way to do this, so I've discovered a really easy way to pass the props to the @keyframes inside makeStyles You just have to create a "helper" hook in order to pass the props:


export const useAnimationStyles = ({ width, duration }: Props) => {
  const classes = makeStyles({
    '@keyframes animation': {
      '0%': {
        transform: 'translateX(0px)',
      },
      '100%': {
        transform: `translateX(${width}px)`,
      },
    },
    scroll: {
      animation: `$animation linear infinite`,
      animationDuration: `${duration}s`
    },
  })

  return classes()
}

and you can use it as usual:

const classes = useAnimationStyles({width, duration})

...

<div className={classes.scroll}
Related