"appear" in CSSTransition doesn't work as expected - css

I'd like to implement CSSTransition to animate an element but still mount it right away.
Based on the documentation:
By default the child component does not perform the enter transition when it first mounts, regardless of the value of in. If you want this behavior, set both appear and in to true.
So I would think that this example would work:
<CSSTransition
in={showMessage}
appear={showMessage}
timeout={300}
classNames="alert"
>
.alert-enter,
.alert-appear {
opacity: 0;
transform: scale(0.9);
}
.alert-enter-active,
.alert-appear-active {
opacity: 1;
transform: translateX(0);
transition: opacity 300ms, transform 300ms;
}
.alert-exit {
opacity: 1;
}
.alert-exit-active {
opacity: 0;
transform: scale(0.9);
transition: opacity 300ms, transform 300ms;
}
Here is a codesandbox: https://codesandbox.io/s/keen-forest-ghgxq?file=/index.js
As you can see it is displayed right away. I need it to be hidden but still mounted. How do I do this?

But you didn't setup the show property of the Alert component. So by default, it is true
Here's how you can hide it in the beginning, then show and unshow, sandbox
Code:
import React, { useEffect, useState } from 'react';
import ReactDOM from 'react-dom';
import { Container, Button, Alert } from 'react-bootstrap';
import { CSSTransition } from 'react-transition-group';
import './styles.css';
function Example() {
const [showMessage, setShowMessage] = useState(false);
useEffect(() => {
setTimeout(() => {
setShowMessage(true);
}, 10000);
}, []);
return (
<Container style={{ paddingTop: '2rem' }}>
<CSSTransition
in={showMessage}
exit={showMessage}
appear={showMessage}
timeout={300}
classNames="alert"
>
<Alert
variant="primary"
dismissible
show={showMessage}
onClose={() => setShowMessage(false)}
>
<Alert.Heading>
Animated alert message
</Alert.Heading>
<p>
This alert message is being transitioned in and
out of the DOM.
</p>
<Button onClick={() => setShowMessage(false)}>
Close
</Button>
</Alert>
</CSSTransition>
<button onClick={() => setShowMessage(true)}>
Show me
</button>
</Container>
);
}
ReactDOM.render(
<Example />,
document.getElementById('root')
);

Related

Position one image over another on react in a specific location and animate

I Want to reply a behavior I saw on a page the map below the section "How It works" title (I wanted to embed a video but it seems stack overflow don't allow it) i.e place one image over another in a specific location, the page I linked shows a map and a pointer that points to the emirates but I can't figure how to do this I achieve this in React, by using position CSS property to position the second image (pointer) relative to the first image (map) and then use the top, left, right, and bottom properties to position the pointer on the desired location on the map but I am having problems with the animation, this is rendering when the parent is rendered and not when the page is scrolled down, I am using the IntersectionObserver
my code is the following:
import React from 'react';
import React, {useEffect, useRef, useState} from 'react';
function MapWithPointer() {
const mapRef = useRef(null);
const pointerRef = useRef(null);
const [isPointerVisible, setIsPointerVisible] = useState(false);
useEffect(() => {
if(!isPointerVisible) return;
const observer = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
setIsPointerVisible(true);
}
});
if(mapRef.current) observer.observe(mapRef.current);
return () => observer.disconnect();
}, [isPointerVisible, mapRef]);
return (
<div ref={mapRef} style={{ position: "relative" }}>
<img src="https://emiride.com/wp-content/uploads/2022/11/map-1024x594.png" alt="map" />
<img
ref={pointerRef}
src="https://emiride.com/wp-content/uploads/2022/11/piont.png"
alt="pointer"
width={'30wh'}
className={`pointer ${isPointerVisible ? "is-visible" : ""}`}
style={{ position: "absolute", top: "310px", left: "640px" }}
/>
</div>
);
}
css:
#keyframes pointer-animation {
from {
transform: translateY(1000%);
}
to {
transform: translateY(0);
}
}
.pointer {
animation: pointer-animation 1s ease-in-out;
transform: translateY(100%);
}
.pointer.is-visible {
transform: translateY(0);
animation: pointer-animation 1s ease-in-out;
}
and int the parent ins rendering like this:
<MapComponent/> , the parent does not have useEffect hook.
how can I achieve my purpose?

React CSSTransition Issues

I am trying to display header one in the beginning and then when clicked on, fade in the second header. However they both are showing up in beginning. My understanding is that the in prop is what controls when the children of get rendered. But for some reason they are being rendered in beginning when showTwo is false. Any help would be much appreciated.
Component
import React, { useState } from "react";
import { CSSTransition } from "react-transition-group";
import "./Intro.css";
function Intro() {
const [showOne, setShowOne] = useState(true);
const [showTwo, setShowTwo] = useState(false);
return (
<>
{showOne && <h1 onClick={() => setShowTwo(true)}>One!</h1>}
<CSSTransition
in={showTwo}
timeout={750}
onEnter={() => setShowOne(false)}
classNames="creation"
>
<h2>Two!</h2>
</CSSTransition>
</>
);
}
export default Intro;
CSS
.creation-enter {
opacity: 0;
}
.creation-enter-active {
opacity: 1;
transition: opacity 700ms;
}
.creation-exit {
opacity: 1;
}
.creation-exit-active {
opacity: 0;
transition: opacity 700ms;
}
I realized that I was missing the prop unmountOnExit and misunderstanding what the in prop is for.
If others stumble upon this with similar issues, in is used to determine when the *-enter, *-enter-active, ... are added as classes.

Animate React Modal

I have a Modal in my web app which I want to slide in when the user clicks "open" button. I am using react-transition-group to achieve this. But I am unable to get the animation working. Not sure what's wrong here?
import React from 'react';
import ReactDOM from 'react-dom';
import { CSSTransition } from 'react-transition-group';
import Modal from 'react-modal';
import './styles.css';
class Example extends React.Component {
state = {
isOpen: false,
};
toggleModal = () => {
this.setState(prevState => ({
isOpen: !prevState.isOpen,
}));
};
render() {
const modalStyles = {
overlay: {
backgroundColor: '#ffffff',
},
};
return (
<div>
<button onClick={this.toggleModal}>
Open Modal
</button>
<CSSTransition
in={this.state.isOpen}
timeout={300}
classNames="dialog"
>
<Modal
isOpen={this.state.isOpen}
style={modalStyles}
>
<button onClick={this.toggleModal}>
Close Modal
</button>
<div>Hello World</div>
</Modal>
</CSSTransition>
</div>
);
}
}
CSS File:
.dialog-enter {
left: -100%;
transition: left 300ms linear;
}
.dialog-enter-active {
left: 0;
}
.dialog-exit {
left: 0;
transition: left 300ms linear;
}
.dialog-exit-active {
left: -100%;
}
Here is the working code.
The problem here is that react-modal uses a react-portal as its mounting point. So it is not rendered as the children of the CSSTransition component. So you could not use the CSSTransition with it.
You can use some custom css to create transition effects. It is in the react-modal documentation.
So if you add this to your css. There will be transition.
.ReactModal__Overlay {
opacity: 0;
transform: translateX(-100px);
transition: all 500ms ease-in-out;
}
.ReactModal__Overlay--after-open {
opacity: 1;
transform: translateX(0px);
}
.ReactModal__Overlay--before-close {
opacity: 0;
transform: translateX(-100px);
}
And we have to add the closeTimeoutMS prop to the modal in order the closing animation to work.
<Modal
closeTimeoutMS={500}
isOpen={this.state.isOpen}
style={modalStyles}
>
https://codesandbox.io/s/csstransition-component-forked-7jiwn

React CSSTransition Help. Animation resetting. and not setting the enter class right away

my React code
import React from 'react'
import ReactDOM from 'react-dom'
import { CSSTransition } from 'react-transition-group'
import './styles.css';
const Fade = ({ children, ...props }) => (
<CSSTransition
{...props}
timeout={600}
classNames="slide-filter"
>
{children}
</CSSTransition>
);
class FadeInAndOut extends React.Component {
state = {
show: false
}
render() {
return (
<div>
<button onClick={() => this.setState((prevState) => {
return { show: !prevState.show }
})}>Toggle</button>
<hr/>
<Fade in={this.state.show}>
<div className='greeting'>Hello world</div>
</Fade>
</div>
)
}
}
My CSS classes
.slide-filter-enter {
transform: translateX(50%);
opacity: 0;
transition: all 0.6s ease-in;
color:blue;
}
.slide-filter-enter-active {
transform: translateX(0);
color:red;
opacity: 1;
}
.slide-filter-exit {
transform: translateY(0);
opacity: 1;
color:red;
}
.slide-filter-exit-active {
color:blue;
transform: translateX(50%);
transition: all 0.6s ease-in;
}
Ok I can't understand why this is not working. It just resets to its original state after animating.
Also why is the "enter" or "enter-active" class not applied the first time it is rendered on the screen?
So you want the position of the "Fade" component to stay at the end position of the animation? Forgive me if this is not the behavior you are looking for but try removing the timeout={1000} prop on line 10.

React CSSTransitionGroup with multiple components

I am trying to build a reusable animated overlay.
However, only the first component mount is detected, meaning that I can only use this overlay once for my whole application. If I use a second one, it won't be animated.
I tried a lot of thing, like using unique keys, transition names and so on, but I can't get this to work.
Here is the current code:
import React from 'react';
import { CSSTransitionGroup } from 'react-transition-group';
import styled from 'styled-componets'
const OverlayDiv = styled.div`
transition: opacity 300ms ease-in;
&._overlay-transition-appear,
&._overlay-transition-enter {
opacity: 0.01;
}
&._overlay-transition-appear._loading-overlay-transition-appear-active,
&._overlay-transition-enter._loading-overlay-transition-enter-active {
opacity: 1;
}
&._overlay-transition-leave {
opacity: 1;
}
&._overlay-transition-leave._loading-overlay-transition-leave-active {
opacity: 0;
}
`;
const animated = (WrappedComponent) => ({ animate = true, ...otherProps }) => {
if (animate) {
return (
<CSSTransitionGroup
transitionName="_overlay-transition"
transitionAppear
transitionEnterTimeout={500}
transitionLeaveTimeout={500}
transitionAppearTimeout={500}
>
<WrappedComponent {...otherProps} />
</CSSTransitionGroup>
);
}
return <WrappedComponent {...otherProps} />;
};
export const Overlay = ({ animate = true, className, parentDimensions, children }) => (
<OverlayDiv
key="overlay" // import for React CSS Transition
className={className}
height={parentDimensions ? `${parentDimensions.offsetHeight}px` : '100%'}
>
{children}
</OverlayDiv>
);
export default animated(Overlay);
Any idea on this ?

Resources