Skip to main content

sometechblog.com

Lightweight and flexible React hook to animate height change

Hiding or showing a element with React is as simple as an if statement deciding whether to print it or not. However often you want to be able to animate the transition, so that it smoothly closes or opens. To avoid cluttering the various components with this animation logic, extract the logic into a hook:

/**
 * Returns the variables needed to animate a open and close functionality via height
 * @param  {Boolean} isOpen:   boolean is the element initially open
 * @param  {Number}  duration: number duration in ms
 */
function useHeightAnimation(isOpen = false, duration = 350) {
  const contentRef = React.useRef(); // Inner wrapper that keeps the height if the outer animated is closed
  const [height, setHeight] = React.useState(isOpen ? 'auto' : 0);

  const handleClick = () => {
    const contentRect = contentRef.current.getBoundingClientRect();

    // Set the height so the element has an initial height to transition from
    setHeight(`${contentRect.height}px`);

    // Set the new desired height, either 0px or full height from the innerRef
    setTimeout(() => setHeight(height === 0 ? `${contentRect.height}px` : 0));

    setTimeout(
      () => {
        if (height === 0) {
          // Set the height to "auto" to prevent issues with resizing when fully opened
          setHeight('auto');
        }
      },
      duration,
      height,
    );
  };

  return { height, handleClick, contentRef };
}

The hook can be used like:

function MyComp(props) {
  const duration = 350;
  const { height, handleClick, contentRef } = useHeightAnimation(false, duration);

  return (
    <div>
      <button onClick={handleClick}>Open or close</button>
      <div
        style={{
          height: height,
          overflow: height === 'auto' ? 'visible' : 'hidden',
          transition: `height ${duration}ms cubic-bezier(0.4, 0, 1, 1)`,
        }}
      >
        <div ref={contentRef}>
          Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore
          et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
          aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
          cillum dolore eu fugiat nulla pariatur.
        </div>
      </div>
    </div>
  );
}