react-transition-group CSSTransition slide in on render - css

I'm trying to have a component conditionally render in React and slide it when it does render
packages:
"react": "^16.8.6",
"react-transition-group": "^4.0.1",
code snippet:
{ expanded && (
<CSSTransition in={expanded} timeout={500} classNames="slide">
<div className="expandedDiv"></div>
</CSSTransition>
)}
css:
.slide-enter {
transform: translateX(-100%);
transition: .3s linear;
}
.slide-enter-active {
transform: translateX(0%);
}
.slide-exit {
transform: translateX(0%);
transition: .3s linear;
}
.slide-exit-active {
transform: translateX(-100%);
}
structure:
+------------------------------+
| | | header |
| | |____________+
| | | content |
| | | |
| | | |
| nav | expanded | |
| | | |
| | | |
| | | |
+------------------------------+
Expanded should slide in on true, and slide out on false, it is expandedDiv from the code snippet
The div just pops in with no animation. Expected behaviour is a linear transition from left to right
Thanks

I need to see a little bit more of your code to understand exactly what you're trying to do. But if I got it right, try doing it like this:
<CSSTransition
in={expanded}
appear={true}
key = {this.props.location.key}
timeout={500}
classNames="slide">
<div className='expandedDiv'> </div>
</CSSTransition>

<CSSTransition
in={expanded}
timeout={300}
classNames="slide"
unmountOnExit
onEnter={() => this.toggleExpanded(true)}
onExited={() => this.toggleExpanded(false)}
>
<div className="expandedDiv">
</div>
</CSSTransition>
</div>

Related

React Transition Group: CSSTransition works on enter, not on exit

I have a React app that is using the CSSTransition component from react-transition-group: when the component appears, everything behaves as expected (a 0.5s transition from opacity: 0 to opacity: 1), however when the component exits, the transition is not applied and it just immediately disappears. Can anybody help me figure out why?
Render method in component:
render(){
const countries = geoUrl.objects.ne_50m_admin_0_countries.geometries;
const { handleEnter, handleList, list } = this.props;
return (
<CSSTransition
classNames="transition"
transitionAppearTimeout={50000}
timeout={500000}
key={ list }
in={ list } // this is a boolean value passed from the parent component, it is initially set to false but changes to true when this component is rendered
unmountOnExit
appear
>
<div className="overlay" id="list">
<div className="wrapper" ref={this.setWrapperRef}>
<aside className="list">
<a className="close" href="#home" onClick={handleList}>×</a>
<ul className="countryList">
{ countries.sort((a, b) => (a.properties.NAME > b.properties.NAME) ? 1 : -1).map(geo =>
geo.properties.COUNTRY ?
<li className="listItem" key={ `${geo.properties.ISO_A3}${geo.properties.name}` }><a href="#country" onClick={() => {
const { NAME, DISH, DESCRIPTION, PHOTO, RECIPE } = geo.properties;
handleEnter(NAME, DISH, DESCRIPTION, PHOTO, RECIPE);
}}>{ geo.properties.NAME }</a></li>
: null
)}
</ul>
</aside>
</div>
</div>
</CSSTransition>
);
}
CSS:
.transition-appear {
opacity: 0.01;
}
.transition-appear.transition-appear-active {
opacity: 1;
transition: opacity .5s ease-in;
}
.transition-enter {
opacity: 0;
}
.transition-enter-active {
opacity: 1;
transition: opacity .5s ease-in;
}
.transition-exit {
opacity: 1;
}
.transition-exit-active {
opacity: 0;
transition: opacity .5s ease-in;
}
I also struggled with the transition out, but have come up with a solution. I can't tell what your final result should look like in the UI, whether you want to transition in between conditionally rendered elements on the page, or just a transition when the component mounts and unmounts, but I think you want to do the former.
To transition between two or more elements on the same page, you will need to wrap your <CSSTransition> tags in <TransitionGroup> tags (and import it alongside CSSTransition). When you do this, you will need to provide a unique key property to the <CSSTransition> tag, it can't just be a boolean like it looks like you have. You also will need to slightly modify your CSS.
.transition-enter {
opacity: 0;
}
.transition-enter.transition-enter-active {
opacity: 1;
transition: opacity 0.5s ease-in;
}
.transition-enter-done {
opacity: 1;
}
.transition-exit {
opacity: 1;
}
.transition-exit.transition-exit-active {
opacity: 0;
transition: opacity 0.5s ease-in;
}
.transition-exit-done {
opacity: 0;
}
And the Transition tags:
import {CSSTransition, TransitionGroup} from "react-transition-group"
//...the rest of your code
return (
<TransitionGroup>
<CSSTransition
key={foo} //something unique to the element being transitioned
classNames="transition"
timeout={500}
>
<div className="overlay" id="list">
<div className="wrapper" ref={this.setWrapperRef}>
<aside className="list">
<a className="close" href="#home" onClick={handleList}>×</a>
<ul className="countryList">
{ countries.sort((a, b) => (a.properties.NAME > b.properties.NAME) ? 1 : -1).map(geo =>
geo.properties.COUNTRY ?
<li className="listItem" key={ `${geo.properties.ISO_A3}${geo.properties.name}` }><a href="#country" onClick={() => {
const { NAME, DISH, DESCRIPTION, PHOTO, RECIPE } = geo.properties;
handleEnter(NAME, DISH, DESCRIPTION, PHOTO, RECIPE);
}}>{ geo.properties.NAME }</a></li>
: null
)}
</ul>
</aside>
</div>
</div>
</CSSTransition>
</TransitionGroup>
)
Please note: You do not need appear, in, or unmountOnExit properties for this method, but you will have issues with duplicate elements appearing in the DOM during the transition, becuase react-transition-group actually clones the element and deletes the old one (which is why it needs a unique key). The only way to achieve a cross-fade transition is to take your elements out of the document flow with position absolute, so they overlap as one transitions in, and the other out.
I can't test your exact code, because there is not enough information, but I put together a very basic codesandbox that demonstrates the method with 2 conditionally rendered elements:
https://codesandbox.io/s/long-sea-9rtw9?file=/src/Test.js

use react-transition-group as child component receives new props

I have a child component where I would like to use slide-out animation as new props are getting passed to it and I try to use react-transition-group/switch-transition but is not really clear how to use it
The child component render method looks as it follows
return (
<SwitchTransition mode="out-in">
<CSSTransition
classNames="slide"
>
<div className={classnames("fields-group", containerClass)}>
{/* <pre>{JSON.stringify(this.props.fields, null, 2)}</pre>*/}
{fields}
</div>
</CSSTransition>
</SwitchTransition>
);
There are more things you need to do:
CSSTransition should has a prop key. When it changed, the transition will take affect.
You need to add the transition styles by yourself because, React Transition Group is not an animation library like React-Motion, it does not animate styles by itself. reference
So the child component will look something like that:
function Child({ propToAnimate }) {
return (
<>
<h4>Child Component</h4>
<div className="main">
<SwitchTransition mode="out-in">
<CSSTransition
key={propToAnimate}
addEndListener={(node, done) => {
node.addEventListener("transitionend", done, false);
}}
classNames="fade"
>
<div className="button-container">
<div className="animate">
<pre>state: {propToAnimate}</pre>
</div>
</div>
</CSSTransition>
</SwitchTransition>
</div>
</>
);
}
And the styles (for slide animation for example):
.fade-enter .animate {
opacity: 0;
transform: translateX(-100%);
}
.fade-enter-active .animate {
opacity: 1;
transform: translateX(0%);
}
.fade-exit .animate {
opacity: 1;
transform: translateX(0%);
}
.fade-exit-active .animate {
opacity: 0;
transform: translateX(100%);
}
.fade-enter-active .animate,
.fade-exit-active .animate {
transition: opacity 500ms, transform 500ms;
}
https://codesandbox.io/s/switchtransition-child-component-dk4jo

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.

Mediawiki table: "efficiently" applying different alignment for different column

How can I efficiently center-align some columns while left-align others?
I want to do something like this.
-------------------------
| A |B |
-------------------------
| C |D |
-------------------------
This code makes all columns centered.
{| class="wikitable" style="text-align: center;"
|-
! Header 1
! Header 2
|-
| A
| B
|-
| C
| D
|}
And I know the following code does what I want.
{| class="wikitable"
|-
! Header 1
! Header 2
|-
| style="text-align: center;" | A
| B
|-
| style="text-align: center;" | C
| D
|}
But since I need to make a quite lenghty table, this is tedious.
Is there any code that will center-align only the 1st column using a very simple one line of code?
The accepted answer, while correct, can be tedious to implement generally, as you need to create a distinct CSS class for every combination of column position and text alignment that you need.
An alternative approach for one-offs is to embed CSS directly into the wiki page. On wikis that are only edited by trusted users, you can enable $wgRawHtml. On others, you can use an extension such as Extension:CSS. If you have multiple tables, you can restrict the styling to each table by using #id selectors.
<html> <!-- assumes $wgRawHtml = true; safer alternatives exist -->
<style>
table#accounts tr td:nth-child(3),
table#accounts tr td:nth-child(4)
{
text-align: right;
}
</style>
</html>
{| class="wikitable" id="accounts"
! Account Number !! Account Name !! Source Balance !! Target Balance
|-
| 1234 || UK Savings || 402.00 || 323.21
|-
| 5432 || Car Fund || 12,943.00 || 23,433.21
|-
| 6789 || Other Expenses || 4.21 || 6.21
|}
Edit: On second thoughts, going with a global approach does result in cleaner syntax within the wiki pages, especially if you have many tables with columns to align. I've created CSS classes for each alignment in the MediaWiki:Common.css page:
table.col-1-center td:nth-child(1) { text-align: center; }
table.col-2-center td:nth-child(2) { text-align: center; }
table.col-3-center td:nth-child(3) { text-align: center; }
table.col-4-center td:nth-child(4) { text-align: center; }
table.col-5-center td:nth-child(5) { text-align: center; }
table.col-6-center td:nth-child(6) { text-align: center; }
table.col-7-center td:nth-child(7) { text-align: center; }
table.col-8-center td:nth-child(8) { text-align: center; }
table.col-9-center td:nth-child(9) { text-align: center; }
table.col-1-right td:nth-child(1) { text-align: right; }
table.col-2-right td:nth-child(2) { text-align: right; }
table.col-3-right td:nth-child(3) { text-align: right; }
table.col-4-right td:nth-child(4) { text-align: right; }
table.col-5-right td:nth-child(5) { text-align: right; }
table.col-6-right td:nth-child(6) { text-align: right; }
table.col-7-right td:nth-child(7) { text-align: right; }
table.col-8-right td:nth-child(8) { text-align: right; }
table.col-9-right td:nth-child(9) { text-align: right; }
Then, within your wiki pages, you can simply reference the CSS class:
{| class="wikitable col-3-right col-4-right"
! Account Number !! Account Name !! Source Balance !! Target Balance
|-
| 1234 || UK Savings || 402.00 || 323.21
|-
| 5432 || Car Fund || 12,943.00 || 23,433.21
|-
| 6789 || Other Expenses || 4.21 || 6.21
|}
The added advantage of this approach is that you don't need to enable $wgRawHtml or install extensions.
Unless you disabled it in LocalSettings.php, you can use the page MediaWiki:Common.css to add extra stylesheets to all pages. Just do what you need there, using plain CSS. E.g:
.myTableClass td {
text-align: left;
}
.myTableClass td:first-child {
text-align: center;
}
...and then add that class to your tables
{| class="wikitable myTableClass"
|-
| A
| B
|-
| C
| D
|}

Resources