Home > other >  Can we animate a CSS change with a State?
Can we animate a CSS change with a State?

Time:07-28

I have a Sidebar on left of my App, and it is set on 300px wide. When I click on a button, the Sidebar goes from 300px to 50px.

I change this width with a state :

const [isMinimized, setIsMinimized] = useState(false);

[...]

<div className={`${isMinimized ? 'w-16' : '2xl:w-80 w-56'} relative bg-white`}>

I'd like to set an animation when the sidebar minimize. I tried to add an animation on my div, but does not work.

Is it possible ?

CodePudding user response:

You can specify a className when isMinimized is true ( for Example isMinimzed ? 'animatedScrollbar w-16' : '2xl:w-80 w-56') and add your transition as css using the className of the minimized state .

CodePudding user response:

You need to add transition-width so tailwind adds transition-property:width to the element's style properties.

You can do this all within JSX with tailwind classes. No need for other code. Check below

function MyApp() {
  const [isMinimized, setIsMinimized] = React.useState(false);

  return ( 
      <div >
        <div 
          className = {
          `${isMinimized ? 'w-16' : '2xl:w-80 w-56'} relative bg-black duration-1000 transition-width ease-in-out`
        } >
          MY DIV 
        </div> 
          <button 
            onClick = {() => setIsMinimized(!isMinimized)} 
          > 
          CLICK 
          </button> 
      </div>
  )
}

ReactDOM.createRoot(
  document.getElementById("root")
).render( <
  MyApp / >
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>
<script src="https://cdn.tailwindcss.com"></script>

Or see jsFiddle

If you want to add custom transition durations or behaviors you would need to change tailwind config. Read more here tailwind transition

CodePudding user response:

Use Web Animation API

First create a ref object of the element you change its width.

const ref = useRef(null);

And use it:

<div ref={ref} className={relative bg-white`}>

Call this function on click.

  const onClick = () => {
    const { current } = ref;
    if (current) {
      const keyframe = [{ width: "300px" }, { width: "50px" }];
      const options = {
        duration: 1000,
        fill: "forwards",
        delay: 0,
        easing: "ease-in",
      };
      const newKeyframeEffect = new KeyframeEffect(current, keyframe, options);
      const animation = new Animation(newKeyframeEffect, document.timeline);
      animation.play();
      animation.onfinish = () => {
        
      }
    }
  };

Do whatever you need in onfinish functoin.


If you need to change the width of the element back to 300px, do this:

Track if the element is expanded.

const [isExpended, setIsExpended] = useState(false)

If expanded, change its width from 300px to 50px. Else vise versa.

const keyframe = isExpended ? [{ width: "50px" }, { width: "300px" }]: [{ width: "300px" }, { width: "50px" }];

When the animation finishes, change the isExpended state.

 setIsExpended(!isExpended)

Example code


const App  = () => {
    const ref = useRef(null)

    const [isExpended, setIsExpended] = useState(false)

    const onClick = () => {
        const { current } = ref;
        if (current) {
            const keyframe = isExpended ? [{ width: "50px" }, { width: "300px" }]: [{ width: "300px" }, { width: "50px" }];

            const options = {
                duration: 1000,
                fill: "forwards",
                delay: 0,
                easing: "ease-in",
            };
            const newKeyframeEffect = new KeyframeEffect(current, keyframe, options);
            const animation = new Animation(newKeyframeEffect, document.timeline);
            animation.play();
            animation.onfinish = () =>  setIsExpended(!isExpended);
        }
    };

    return <div ref={ref} style={{width: "300px", background: "red"}}>
        <button onClick={onClick} type="button">Click</button>
    </div>
}

Try this

https://stackblitz.com/edit/react-17rkkx?file=src/App.js

Reference

  1. useRef - https://reactjs.org/docs/hooks-reference.html#useref
  2. Web Animation API - https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API
  • Related