3

Trying to get used CSSTransiction component. I need to show a panel which is animated by using css-classes. The first class defines the primary location, the second defines position when the panel is opened (top: 0).

Appearing is working, but exiting does not. onEntered fires, onExied does not.

There is lack of documentation for CSSTransition component, I tried different combinations, but without success. Any ideas?

CSS:

.getSecondLevelPanel{
    position: fixed;
    left: 450px;
    top: -100%;
    height: 100%;
    width: 400px;
    transition: all 250ms ease-out;
}

.getSecondLevelPanelOpened {
    top: 0;
}  

React component:

import * as React from 'react';
import { CSSTransition } from 'react-transition-group';

export interface Props {
    isVisible: Boolean;
    children: React.ReactChild;
    onClose: () => void;
}

const SecondLevelPanel = (props: Props) => {
  return (
    <CSSTransition
        timeout={{
            enter: 0,
            exit: 500
        }}
        in={props.isVisible}
        appear={true}
        enter={true}
        exit={true}
        classNames={{
            appear: 'getSecondLevelPanel',
            enterDone: 'getSecondLevelPanel getSecondLevelPanelOpened',
            exit: 'getSecondLevelPanel'
        }}
        unmountOnExit={true}
        onEntered={() => {
            alert('entered');
        }}
        onExited={() => {
            alert('exited');
        }}
    >
        <div>
            <a onClick={() => props.onClose()}>Close</a>
            {props.children}
        </div>
    </CSSTransition>
  );
};

export default SecondLevelPanel;
podeig
  • 2,597
  • 8
  • 36
  • 60

3 Answers3

3

The problem is in your CSS and classNames prop. The CSSTransition component applies the classes like so.

  1. appear and enter classes are added as soon as the in prop is set to true.
  2. appear-active and enter-active are added right after the appear and enter classes are set.
  3. appear-done and enter-done are added after the duration set in the timeout passed.
  4. the exit classes repeat Step 1-3 just after the in prop is set to false.

The reason your exit calls don't work is probably due to only setting one exit class and 0 set to your enter duration. Try setting your transition rule on the active classes to ensure that the transition is set for the whole duration of the transition and separate the moving parts from the static ones. Like so

.panel{
    position: fixed;
    left: 450px;
    top: -100%;
    height: 100%;
    width: 400px;
}

.panel-appear,
.panel-enter {
   top: -100%;
}

.panel-appear-active,
.panel-enter-active {
    top: 0;
    transition: all 250ms ease-out;
}

.panel-exit {
    top: 0;
}

.panel-exit-active {
    top: -100%
    transition: all 250ms ease-out;
}

Take a look at this codepen, this is how I create a panel transitions.

Geoff Taylor
  • 496
  • 3
  • 17
3

After searching for answers for sometime, I realised my problem had to do with my toggle function (onClick={() => props.onClose()} in your case). It seems my toggle function was not working as it was supposed to. Since onEntered is triggered with "in{true}" and onExited is triggered with "in{false}", you have to make sure the boolean is being changed with each click on your anchor tag. Looking at your code is seems your onClose function only returns a void function instead of a toggle. Try toggling between true and false and pass that into the in{//toggle function} param.

1

Install:

npm install react-transition-group

Usage:

import { CSSTransition } from 'react-transition-group';

<CSSTransition
  in={toShow} // boolean value passed via state/props to either mount or unmount this component
  timeout={300}
  classNames='my-element' // IMP!
  unmountOnExit
>
  <ComponentToBeAnimated />
</CSSTransition>

NOTE: Make sure to apply below styles using the class property in CSS:

.my-element-enter {
  opacity: 0;
  transform: scale(0.9);
}
.my-element-enter-active {
  opacity: 1;
  transform: translateX(0);
  transition: opacity 300ms, transform 300ms;
}
.my-element-exit {
  opacity: 1;
}
.my-element-exit-active {
  opacity: 0;
  transform: scale(0.9);
  transition: opacity 300ms, transform 300ms;
}
Harshal
  • 7,562
  • 2
  • 30
  • 20