<div id="root" class="panel center text-center"></div>
.app {
  padding: 10px;
}

.box {
  margin: 10px auto;
}
import React, {
  useLayoutEffect,
  useEffect,
  useRef,
} from "https://esm.sh/react@19.0.0";
import ReactDOM from "https://esm.sh/react-dom@19.0.0/client";

import gsap from "https://esm.sh/gsap";
import { useGSAP } from "https://esm.sh/@gsap/react?deps=react@19.0.0";

gsap.registerPlugin(useGSAP);

console.clear();

const FadeIn = ({ children, stagger = 0, x = 0, ref }) => {
  const el = useRef();
  const animation = useRef();

  useGSAP(() => {
    animation.current = gsap.from(el.current.children, {
      opacity: 0,
      stagger,
      x
    });
  });

  useGSAP(() => {
    // forward the animation instance
    if (typeof ref === "function") {
      ref(animation.current);
    } else if (ref) {
      ref.current = animation.current;
    }
  }, [ref]);

  return <span ref={el}>{children}</span>;
};

function App() {
  const animation = useRef();

  const toggle = () => {
    animation.current.reversed(!animation.current.reversed());
  };

  return (
    <div className="app">
      <div>
        <button onClick={toggle}>Toggle</button>
      </div>
      <FadeIn stagger={0.1} x={100} ref={animation}>
        <div className="box gradient-blue">Box 1</div>
        <div className="box gradient-blue">Box 2</div>
      </FadeIn>
    </div>
  );
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
View Compiled

External CSS

  1. https://codepen.io/GreenSock/pen/xxmzBrw.css

External JavaScript

  1. https://codepen.io/GreenSock/pen/NWoLXRG.js