Stanko / react-animate-height

Lightweight React component for animating height using CSS transitions. Slide up/down the element, and animate it to any specific height.
https://muffinman.io/react-animate-height
MIT License
756 stars 53 forks source link

React Animate Height

npm version npm downloads

No dependencies React component for animating height using CSS transitions. Slide an element up and down or animate it to any specific height. Content's opacity can be optionally animated as well (check animateOpacity prop bellow).

CSS classes are applied in specific animation states, check animationStateClasses prop.

Changelog

Version 3

This is version 3.x branch, rewritten to hooks, which means you'll need React version 16.8 or newer.

For version 2.x, check v2 branch

Breaking changes:

Demo

Live demo: muffinman.io/react-animate-height

Because multiple people asked how to animate list items, I created this simple example for that as well.

To build the examples locally, run:

npm install
npm start

Then open http://127.0.0.1:8000/ in your browser of choice browser.

Or play with this sandbox.

Quick start

Get it from npm

$ npm install --save react-animate-height

Import and use it in your React app.

import React, { useState } from 'react';
import AnimateHeight from 'react-animate-height';

const Example = () => {
  const [height, setHeight] = useState(0);

  return (
    <div>
      <button
        aria-expanded={height !== 0}
        aria-controls="example-panel"
        onClick={() => setHeight(height === 0 ? 'auto' : 0)}
      >
        {height === 0 ? 'Open' : 'Close'}
      </button>

      <AnimateHeight
        id="example-panel"
        duration={500}
        height={height} // see props documentation below
      >
        <h1>Your content goes here</h1>
        <p>Put as many React or HTML components here.</p>
      </AnimateHeight>
    </div>
  );
};

Props

Additional props will be passed to the wrapper div, to make adding attrs like aria-* easier.

Accessibility

Library will hide the content using display: hidden when height props is 0. It will also apply aria-hidden="true" in the same case, but you can override it by passing aria-hidden prop yourself.

When using a button to toggle height, make sure you add aria-expanded and aria-controls to make everything accessible. Here's an example:

<button
  aria-expanded={ height !== 0 }
  aria-controls="example-panel" // it has to match the id passed to AnimateHeight
  onClick={ toggleHeight } // your click handler that toggles height
  // ... all other props
>
  Toggle
</button>

<AnimateHeight id="example-panel">
  Content
</AnimateHeight>

Reduced motion

Component checks for prefers-reduced-motion on start and disables animations if it is set to true. Please note that component doesn't listen for potential changes of prefers-reduced-motion option.

Animate height on content change

It is not built in, but you can use AnimateHeight and ResizeObserver to automatically animate height on content change. I created a small example for you here:

Gotchas

Collapsing margins

While it is animating, component has overflow: hidden. When the animation is finished and height is set to "auto", overflow: hidden is removed. At that moment, any margins you have on the content inside AnimateHeight will collapse, causing content to "jump". To avoid this, just use padding inside the AnimateHeight instead of margins.

Bounded flexboxes

If AnimateHeight is a flex child and it's parent has a fixed height, animation won't work. To fix this, you just need to add the following CSS rule to the AnimateHeight instance.

flex-shrink: 0;

You can do it by passing a className or directly in the style prop

<AnimateHeight style={{flexShrink: 0}}>

Check the issue #89 for the example and more details.

License

MIT