DEV Community

Rohan Bagchi
Rohan Bagchi

Posted on • Updated on • Originally published at rohanbagchi.hashnode.dev

Preview and View More Animation with React Transition Group

Preview and View More animation diagram

Using React Transition Group for a Preview & View More kind of layout animation where the Preview & View More components are different.

At a high level, we can think of several ways of CSS animation we can attempt. In this blog, we will speak about Preview & View More kind of layout where the Preview & View More components are different.

Only prerequitite is that the approximate heights of the Expanded content & Collapsed content are known beforehand as we will be animating on the max-height property.

Now if we are to replace the Expanded content with Collapsed content during collapse phase, it happens abruptly with a jank. To resolve this, we should adopt the following animation strategy:

During expand phase

  1. Replace the Collapsed content with Expanded content
  2. Animate height to accomodate Expanded content

During collapse phase

  1. Animate height to Collapsed content height. This is because the Expanded content is taller than the Collapsed content and can accomodate the height transition without abruptly shrinking

  2. Replace the Expanded content with Collapsed content once animation is over

To achieve this, we will be using CSSTransition module of the react-transition-group

Let's say we have the following Collapsed content component

const CollapsedContent = (props) => {
  return (
    <div className="collapsed">
      <p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>
      <p>
        Asperiores iste magnam dolores eius ab laboriosam excepturi, consectetur
        consequuntur maiores at voluptas ipsam cum reiciendis assumenda tenetur
        natus in omnis deleniti.
      </p>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

And the following Expanded content component

const ExpandedContent = (props) => {
  return (
    <div className="expanded">
      <p>
        It is a long established fact that a reader will be distracted by the
        readable content of a page when looking at its layout. The point of
        using Lorem Ipsum is that it has a more-or-less normal distribution of
        letters, as opposed to using 'Content here, content here', making it
        look like readable English.
      </p>
      <p>
        There are many variations of passages of Lorem Ipsum available, but the
        majority have suffered alteration in some form, by injected humour, or
        randomised words which don't look even slightly believable.
      </p>
      <p>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Asperiores iste
        magnam dolores eius ab laboriosam excepturi, consectetur consequuntur
        maiores at voluptas ipsam cum reiciendis assumenda tenetur natus in
        omnis deleniti.
      </p>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

In the main or orchestrating component, we need to add 2 booleans:

  1. isCollapsed (to track which component to render)
  2. isAnimating (to track when to run animation)

So when the animation is starting, we will toggle isCollapsed to false and when animation has finished, we will toggle isCollapsed to true.

This way we will be able to animate based on the strategy mentioned above.

Main component

export const Main = () => {
  const [isCollapsed, setIsCollapsed] = useState(true);
  const [isAnimating, setIsAnimating] = useState(false);

  return (
    <div>
      <div className="card">
        <CSSTransition
          in={isAnimating}
          timeout={200}
          classNames="content-switching"
          onEntering={() => {
            setIsCollapsed(false);
          }}
          onExited={() => {
            setIsCollapsed(true);
          }}
        >
          <div className="base">
            {isCollapsed && <CollapsedContent />}
            {!isCollapsed && <ExpandedContent />}
          </div>
        </CSSTransition>
      </div>
      <button
        onClick={() => setIsAnimating((prev) => !prev)}
        style={{ display: "block" }}
      >
        {isCollapsed ? "Show" : "Hide"}
      </button>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

As we see here, the user clicking on the Show or Hide button only toggles the isAnimating flag.

The CSSTransition component then handles toggling the isCollapsed flag based on it's life cycle methods: onEntering and onExited.

Finished result:

Full source code is available here:

github.com/rohanBagchi/react-height-animation-tryout

Thank you for reading this far.

Top comments (1)

Collapse
 
sloan profile image
Sloan the DEV Moderator

Hi there, we encourage authors to share their entire posts here on DEV, rather than mostly pointing to an external link. Doing so helps ensure that readers don’t have to jump around to too many different pages, and it helps focus the conversation right here in the comments section.

If you choose to do so, you also have the option to add a canonical URL directly to your post.