Install library from npm via terminal npm i react-transition-group Transition
function TransitionCmpt() {
const ref = useRef()
const [inProp, setInProp] = useState(false)
const transitionStateObj = {
onEnterTrigger: false, onEnterTimeStamp: null, onEnterWidth: null,
onEnteringTrigger: false, onEnteringTimeStamp: null, onEnteringWidth: null,
onExitTrigger: false, onExitTimeStamp: null, onExitWidth: null,
onExitingTrigger: false, onExitingTimeStamp: null, onExitingWidth: null,
onExitedTrigger: false, onExitedTimeStamp: null, onExitedWidth: null,
}
const [transitionData , setTransitionData ] = useState(transitionStateObj)
const resetTransitionData = () => setTransitionData(transitionStateObj)
const initCss = { background: 'yellow', margin: '5px 0px', whiteSpace: 'nowrap', width: '1000px', border: '1px solid grey', height: '20px' }
const transitionCss = {
entering: { width: '10px', transition: `all ${100}ms linear` },
entered: { width: '600px', transition: `all ${200}ms linear` },
exiting: { width: '200px', transition: `all ${300}ms linear` },
exited: { width: '100px', transition: `all ${400}ms linear` },
}
return (
<>
<button
onClick={() => {
setInProp(!inProp)
resetTransitionData()
}}
>
Toggle transition
</button>
<Transition
in={inProp}
timeout={{ enter: 5000, exit: 2000 }}
onEnter={() => setTransitionData({...transitionData, onEnterTrigger:true, onEnterTimeStamp: Date.now(), onEnterWidth: ref.current.style.width})}
onEntering={() => setTransitionData({...transitionData, onEnteringTrigger:true, onEnteringTimeStamp: Date.now(), onEnteringWidth: ref.current.style.width})}
onEntered={() => setTransitionData({...transitionData, onEnteredTrigger:true, onEnteredTimeStamp: Date.now(), onEnteredWidth: ref.current.style.width})}
onExit={() => setTransitionData({...transitionData, onExitTrigger:true, onExitTimeStamp: Date.now(), onExitWidth: ref.current.style.width})}
onExiting={() => setTransitionData({...transitionData, onExitingTrigger:true, onExitingTimeStamp: Date.now(), onExitingWidth: ref.current.style.width})}
onExited={() => setTransitionData({...transitionData, onExitedTrigger:true, onExitedTimeStamp: Date.now(), onExitedWidth: ref.current.style.width})}
>
{state => (
<div style={{ ...initCss, ...transitionCss[state] }} ref={ref}></div>
)}
</Transition>
<div>
{transitionData.onEnterTrigger && <div>onEnter: {0}ms</div>}
{transitionData.onEnteringTrigger && <div>onEntering: {transitionData.onEnteringTimeStamp - transitionData.onEnterTimeStamp}ms</div>}
{transitionData.onEnteredTrigger && <div>onEntered: {transitionData.onEnteredTimeStamp - transitionData.onEnteringTimeStamp}ms</div>}
{transitionData.onExitTrigger && <div>onExit: {0}ms</div>}
{transitionData.onExitingTrigger && <div>onExiting: {transitionData.onExitingTimeStamp - transitionData.onExitTimeStamp}ms</div>}
{transitionData.onExitedTrigger && <div>onExited: {transitionData.onExitedTimeStamp - transitionData.onExitingTimeStamp}ms</div>}
</div>
</>
)
}
CSS Transition CSSTransition applies a pair of class names during the appear, enter, and exit states of the transition. We can style them in CSS. Classes are applied in following sequence: *-appear , *-appear-active , *-appear-done *-enter , *-enter-active , *-enter-done *-exit , *-exit-active , *-exit-done Following props exist:
<CSSTransition
in={showMessage}
timeout={{
appear: 2000,
enter: 300,
exit: 1000,
}}
classNames="xxx"
appear
enter
exit
mountOnEnter
unmountOnExit
onEnter={func}
onEntering={func}
onEntered={func}
onExit={func}
onExiting={func}
onExited={func}
addEndListener={(node, done) => {
node.addEventListener('transitionend', done, false);
}}
>
<p>Hello</p>
</CSSTransition>
Full code.
import { CSSTransition } from 'react-transition-group'
function CSSTransitionCmpt() {
const [showMessage, setShowMessage] = useState(true)
const toggle = () => setShowMessage(!showMessage)
return (
<div>
<button onClick={toggle}>Toggle</button>
<CSSTransition
in={showMessage}
classNames="xxx"
// timeout={300}
timeout={{
appear: 2000,
enter: 300,
exit: 1000,
}}
appear = {true}
unmountOnExit = {true}
>
<p className='animated-element'>Hello</p>
</CSSTransition>
<style jsx global>{`
.xxx-appear {
background: yellow;
}
.xxx-appear-active {
background: green;
transition: background 2000ms;
}
.xxx-appear-done {
background: blue;
}
.xxx-enter {
opacity: 0;
transform: scale(0);
}
.xxx-enter-active {
opacity: 1;
transform: scale(1);
transition: all 300ms;
}
.xxx-enter-done {
background: red;
transition: all 5000ms;
}
.xxx-exit {
opacity: 1;
transform: scale(1);
}
.xxx-exit-active {
opacity: 0;
transform: scale(0);
transition: all 1000ms;
}
.animated-element {
border: 1px grey solid;
margin: 5px;
padding: 5px;
}
`}</style>
</div>
)
}
If appear prop is on then *-appear-done & *-enter-done classes will be both applied. Slide sideways Following approach is used in folded navigation menu slide animation on top of this page.
function SlideSideways() {
const [state, setState] = useState(true)
const toggle = () => setState(!state)
const [radioValueState, setRadioValueState] = useState('forward')
const onValueChange = e => setRadioValueState(e.target.value)
return (
<div className='outer'>
<form>
<p>Direction</p>
<label>
<input
type="radio"
name="name"
value={'forward'}
checked={radioValueState === 'forward'}
onChange={onValueChange}
/>
Forward
</label>
<br />
<label>
<input
type="radio"
name="name"
value={'backwards'}
checked={radioValueState === 'backwards'}
onChange={onValueChange}
/>
Backwards
</label>
<br />
</form>
<button onClick={toggle}>Toggle</button>
<CSSTransition
in={state}
classNames={radioValueState}
timeout={{
appear: 500,
enter: 500,
exit: 500,
}}
appear={true}
unmountOnExit={true}
mountOnEnter={false}
>
<div className={'slide-container ' + radioValueState}>1</div>
</CSSTransition>
<CSSTransition
in={!state}
classNames={radioValueState}
timeout={{
appear: 500,
enter: 500,
exit: 500,
}}
appear={true}
unmountOnExit={true}
mountOnEnter={false}
>
<div className={'slide-container ' + radioValueState}>2</div>
</CSSTransition>
<style jsx>{`
.outer {
position: relative;
width: 100%;
border: 1px dotted grey;
}
.slide-container {
position: absolute;
border: 1px grey solid;
width: 50px;
height: 50px;
left: 50%;
top: 20%;
display: flex;
justify-content: center;
align-items: center;
}
.forward-appear {
transform: translateX(-150%);
}
.forward-appear-active {
transform: translateX(0%);
transition: all 0.5s linear;
}
.forward-appear-done {
transform: translateX(0%);
}
.forward-enter {
transform: translateX(-150%);
}
.forward-enter-active {
transform: translateX(0%);
transition: all 0.5s linear;
}
.forward-enter-done {
transform: translateX(0%);
}
.forward-exit {
transform: translateX(0%);
}
.forward-exit-active {
transform: translateX(150%);
transition: all 0.5s linear;
}
.forward-exit-done {
transform: translateX(150%);
}
.backwards-appear {
transform: translateX(150%);
}
.backwards-appear-active {
transform: translateX(0%);
transition: all 0.5s linear;
}
.backwards-appear-done {
transform: translateX(0%);
}
.backwards-enter {
transform: translateX(150%);
}
.backwards-enter-active {
transform: translateX(0%);
transition: all 0.5s linear;
}
.backwards-enter-done {
transform: translateX(0%);
}
.backwards-exit {
transform: translateX(0%);
}
.backwards-exit-active {
transform: translateX(-150%);
transition: all 0.5s linear;
}
.backwards-exit-done {
transform: translateX(-150%);
}
`}</style>
</div>
)
}