Animate Auto with React Spring
Tags: react, reactspring
Published: 2019-12-24 10:27:20

---
title: "Animate Auto with React Spring"
date: "2019-12-24 10:27:20"
description: "Animating auto height or width is always a tricky matter. With React Spring and a couple hooks, we can build a super-slick accordion component."
tags: ["React", "ReactSpring"]
canonical_url: "https://www.chrisberry.io/Animate-Auto-With-React-Spring/"
---

Animating auto height or width is always a tricky matter. While there are a number of approaches that get you [part way there](https://css-tricks.com/using-css-transitions-auto-dimensions/). Javascript is the only answer that gets us what we’re really looking for.

If you’re using react, then there’s a good chance you’ve already come across [React Spring](https://www.react-spring.io/). If you haven’t, be warned, plain old CSS transitions just won’t cut it once you’ve discovered the beauty of physics-based animations.

Now, React Spring does have a couple of nice examples of animating auto on its site but neither really demonstrates animating auto in an unconstrained context (that is no limit on its height and/or width).

What we’ll be building today is an accordion which upon toggling, gets the height of its content and animates to that value. See below for an example of the final product:

{% codesandbox animate-auto-height-6trvh module=/src/accordion.js %}

## So what’s happening here?

Let’s break down the code piece by piece…

### The Components State

```JSX
const defaultHeight = "100px";

// Manages the open or cloased state of the accordion
const [open, toggle] = useState(false);

// The height of the content inside of the accordion
const [contentHeight, setContentHeight] = useState(defaultHeight);
```

In the above code, we’re using two instances of React’s useState hook. The first holds the “open” state of the accordion (either `true` or `false`). The second holds the height of the accordion’s content.

### useMeasure

```JSX
// Gets the height of the element (ref)
const [ref, { height }] = useMeasure();
```

Next, we have a custom hook provided by the [React Use](https://github.com/streamich/react-use/blob/master/docs/useMeasure.md) library. useMeasure takes advantage of the [Resize Observer API](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver) to measure the size of the target container.

### React Spring

```JSX
// Animations
const expand = useSpring({
  config: { friction: 10 },
  height: open ? `${contentHeight}px` : defaultHeight
});
const spin = useSpring({
  config: { friction: 10 },
  transform: open ? "rotate(180deg)" : "rotate(0deg)"
});
```

Now for the exciting part; configuring our springs. We’re using two here. One for the container and another for the button trigger. One point worth noting is that we're using a template literal to transform the number provided by the `useMeasure` hook to a string which can be interpolated by React Spring. Another important point to note is that we don't access the value of `height` directly (we'll get to the reason why shortly). 

### Get the Height

```JSX
useEffect(() => {
  //Sets initial height
  setContentHeight(height);

  //Adds resize event listener
  window.addEventListener("resize", setContentHeight(height));

  // Clean-up
  return window.removeEventListener("resize", setContentHeight(height));
}, [height]);
```

The last piece before our `return`  portion of our component is a  `useEffect`  hook. We're using it here to get the height of the accordion content upon the mounting of the component, as well as adding an event listener to update the `contentHeight`  whenever the window is resized. A moment ago, I highlighted the fact that we aren't referencing the `height`  value in our spring. What I've noticed with `useMeasure` (resize observer) is that it deals in units smaller than pixels. Consequently, even if there is no resize or animation occurring, useMeasure will sometimes report different sizes continuously (e.g. 750.10, 750.90, 750.95).  If we had referenced `height` instead of `contentHeight` spring would constantly try to animate to the different values.  While this may or may not result in performance issues, it just feels wrong to be animating between values which are imperceptible.

### The Markup

```JSX
return (
  <div className={style.wrapper}>
    <animated.div className={style.accordion} style={expand}>
      <div ref={ref} className={style.content}>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit...
        </p>
      </div>
    </animated.div>
    <animated.button
      className={style.expand}
      onClick={() => toggle(!open)}
      style={spin}
    >
      <FontAwesomeIcon icon={faChevronDown} />
    </animated.button>
  </div>
);
```

The markup of our component is fairly straightforward. The two `style`  attributes are referencing our springs. As React Spring interpolates the values of the CSS properties the styles will, in turn, be updated. For this animating to occur, we need to prepend the element name with `animated`. The `ref` on the first child of the first `animated.div` binds the `useMeasure` hook to this element. And last but not least, we have the `onClick` event handler which toggles the `open` state of our accordion.

Here is the final product:

{% codesandbox animate-auto-height-6trvh module=/src/accordion.js %}