Categories: React

Transition With React Transition Group

In this article, we will learn how we can grouping transition effect in react. We are going to use ‘react-transition-group’ for this.

The Transition component lets you describe a transition from one component state to another. Most commonly it’s used to animate the mounting and unmounting of a component, but can also be used to describe in-place transition states as well.

If you are new to react or follow the steps to create a react app from here. I assume you have already created a react app. Now you need to follow the below steps.

At first we have to install react-router-dom for easy routing.

npm i react-router-dom --save

Install react-transition-group, to install this you need to execute the below command in the terminal.

npm i react-transition-group --save

Now We have to create 2 or 3 components or pages, Here I have created Home.js, Page.js, Subpage.js, Nav.js in src folder.

So, create Home.js file and add below code

import React, { Component } from "react";
import {Link} from 'react-router-dom'
export default class Home extends Component {

constructor(props){
  super(props)
}
 render() {
  return (
   <div className={this.props.active ? "page page_open" : "page page_close"}>
   <div className="page-internal">
    <h1>Home</h1>
    <p>Hello from the home page!</p>
    <Link to="/subpage" className="link">Click here to go to Subpage</Link>
    </div>
   </div>
  )
 }
}

Now create Page.js file and add below code

import React, { Component } from "react";

export default class Page extends Component {

  constructor(props) {
    super(props)
  }

  render() {
    return (
      <div className={this.props.active ? "page page_open" : "page page_close"}>
        <div className="page-internal">
          
          <h1>Page</h1>
          <p>Hello from Page!</p>
        </div>
      </div>
    )
  }
}

Now create Subpage.js file and add below code

import React, { Component } from "react";
import {Link} from 'react-router-dom'
export default class Subpage extends Component {

constructor(props){
  super(props)
}
 render() {
  return (
   <div className={this.props.active ? "page page_open" : "page page_close"}>
   <div className="page-internal">
    <h1>Subpage</h1>
    <p>Hello from a sub page!</p>
    <Link to="/" className="link">Click here to go to Home</Link>
    </div>
   </div>
  )
 }
}

And for Nav menu I have created Nav.js file, add below code in that

import React from 'react'
import { Link } from 'react-router-dom'


export default class Nav extends React.Component {
  render() {
    return (
      <div className={this.props.active ? "pages-nav pages-nav_open" : "pages-nav"}>

        <div className="pages-nav__item">
          <Link to="/" className="link link_page">Home</Link>
        </div>
        <div className="pages-nav__item">
          <Link to="/page" className="link link_page">Page</Link>
        </div>
        <div className="pages-nav__item">
          <Link to="/subpage" className="link link_page">Subpage</Link>
        </div>        
      </div>
    )
  }
}

For some styling add below code in App.css file

html, body, #root {overflow: hidden;height: 100vh;}
body {
    margin: 0;
    padding: 0;
    font-family: Helvetica, Arial, sans-serif;
    color: #cecece;
    background: #1d1e21;
}
.App {position: relative;}
a{text-decoration: none;}
/* fade transition effect  */.fade-enter{
  transform: translate3d(0px, 75%, -150px) ;
  z-index: 8;
  opacity: 0.9;
}
.fade-enter.fade-enter-active {
  opacity: 1;
  z-index: 8;
  transform: translate3d(0px, 0px, 0px) ;
  -webkit-transition: -webkit-transform 0.45s, opacity 0.45s;
  transition: transform 0.45s, opacity 0.45s ;
  -webkit-transition-timing-function: cubic-bezier(0.6, 0, 0.4, 1);
  transition-timing-function: cubic-bezier(0.6, 0, 0.4, 1) ;
}
.fade-exit {
  position: absolute ;
  top: 0px;
  left: 0;
  opacity: 1;
}
.fade-exit.fade-exit-active {
  opacity: 0.9;
  transform: translate3d(0px, 100%, 0px);
  -webkit-transition: -webkit-transform 0.45s, opacity 0.45s ;
  transition: transform 0.45s, opacity 0.45s ;
  -webkit-transition-timing-function: cubic-bezier(0.6, 0, 0.4, 1);
  transition-timing-function: cubic-bezier(0.6, 0, 0.4, 1) ;
}
/* Menu button */.menu-button {
  position: absolute;
  z-index: 1000;
  top: 30px;
  left: 30px;
  width: 30px;
  height: 24px;
  padding: 0;
  cursor: pointer;
  border: none;
  outline: none;
  background: transparent;
}
.no-js .menu-button {display: none;}
.menu-button::before, .menu-button::after, .menu-button span {background: #5f656f;}
.menu-button::before,.menu-button::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 0;
  width: 100%;
  height: 2px;
  pointer-events: none;
  -webkit-transition: -webkit-transform 0.25s;
  transition: transform 0.25s;
  -webkit-transform-origin: 50% 50%;
  transform-origin: 50% 50%;
}
.menu-button span {
  position: absolute;
  left: 0;
  overflow: hidden;
  width: 100%;
  height: 2px;
  text-indent: 200%;
  -webkit-transition: opacity 0.25s;
  transition: opacity 0.25s;
}
.menu-button::before {-webkit-transform: translate3d(0, -10px, 0) scale3d(0.8, 1, 1); transform: translate3d(0, -10px, 0) scale3d(0.8, 1, 1);}
.menu-button::after { -webkit-transform: translate3d(0, 10px, 0) scale3d(0.8, 1, 1);transform: translate3d(0, 10px, 0) scale3d(0.8, 1, 1);}
.menu-button_open span {opacity: 0;}
.menu-button_open::before { -webkit-transform: rotate3d(0, 0, 1, 45deg); transform: rotate3d(0, 0, 1, 45deg);}
.menu-button_open::after {-webkit-transform: rotate3d(0, 0, 1, -45deg); transform: rotate3d(0, 0, 1, -45deg);}
/* Pages stack */.pages-stack {
  z-index: 100;
  pointer-events: none;
  -webkit-perspective: 1200px;
  perspective: 1200px;
  -webkit-perspective-origin: 50% -50%;
  perspective-origin: 50% -50%;
}
.page {
  position: relative;
  z-index: 5;
  overflow: hidden;
  width: 100%;
  height: 100vh;
  pointer-events: auto;
  background: #2a2a2a;
  box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1);
}
.pages-stack_open .page {
  cursor: pointer;
  -webkit-transition: -webkit-transform 0.45s, opacity 0.45s;
  transition: transform 0.45s, opacity 0.45s;
  -webkit-transition-timing-function: cubic-bezier(0.6, 0, 0.4, 1);
  transition-timing-function: cubic-bezier(0.6, 0, 0.4, 1);
}
.pages-stack .page {
  cursor: pointer;
  -webkit-transition: -webkit-transform 0.45s, opacity 0.45s;
  transition: transform 0.45s, opacity 0.45s;
  -webkit-transition-timing-function: cubic-bezier(0.6, 0, 0.4, 1);
  transition-timing-function: cubic-bezier(0.6, 0, 0.4, 1);
}
.page-inactive {
  position: absolute;
  z-index: 0;
  top: 0;
  opacity: 0;
}
.page-inactive2 {
  position: absolute;
  z-index: 0;
  top: 0;
  opacity: 0;
}
.page_open{
    z-index: 9;
    opacity: 1;
    transform: translate3d(0px, 30%, -220px);
}
.page_close{
    z-index: 9;
    opacity: 1;
    transform: translate3d(0px, 0px, 0px);
}
.page-inactive_open{
    transform: translate3d(0px, 30%, -150px);
    z-index: 8; 
    opacity: 0.9;
}
.page-inactive_close{
    transform: translate3d(0px, 100%, 0px);
    z-index: 8;
    opacity: 0.9;
}
.page-inactive2_open{
    transform: translate3d(0px, 30%, -300px);
    z-index: 7;
    opacity: 0.8;
}
.page-inactive2_close{
    transform: translate3d(0px, 100%, 0px);
    z-index: 7;
    opacity: 0.8;
}
.page-internal{ padding:70px;}
.pages-nav {
  display: -webkit-flex;
  display: flex;
  -webkit-flex-wrap: wrap;
  flex-wrap: wrap;
  -webkit-justify-content: center;
  justify-content: space-around;
  -webkit-align-itrems: center;
  align-items: center;
  text-align: center;
  background: #0e0f0f;
  position: absolute;
  top: 0;
  left: 0;
  box-sizing: border-box;
  width: 100%;
  padding: 30px;
  pointer-events: none;
  opacity: 0;
  background: transparent;
  -webkit-transition: -webkit-transform 1.2s, opacity 1.2s;
  transition: transform 1.2s, opacity 1.2s;
  -webkit-transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);
  transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);
  -webkit-transform: translate3d(0, 150px, 0);
  transform: translate3d(0, 150px, 0);
}
.pages-nav_open {
  pointer-events: auto;
  opacity: 1;
  -webkit-transform: translate3d(0, 0, 0);
  transform: translate3d(0, 0, 0);
}
.pages-nav_item {
  width: 33%;
  padding: 1rem;
  box-sizing: border-box;
}
.pages-nav_item {
  padding: 0 10%;
}
.link {
  font-size: 0.85rem;
  font-weight: bold;
  position: relative;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: #fff;
}
.link:hover,.link:focus { color: #fff;}
.link_page {display: block; color: #cecece;}
.link_page:not(.link_faded)::before {
  content: '';
  position: absolute;
  top: 100%;
  left: 50%;
  width: 30px;
  height: 2px;
  margin: 5px 0 0 -15px;
  background: #fff;
  -webkit-transition: -webkit-transform 0.3s;
  transition: transform 0.3s;
  -webkit-transform: scale3d(0, 1, 1);
  transform: scale3d(0, 1, 1);
}
.link_page:hover:before {-webkit-transform: scale3d(1, 1, 1); transform: scale3d(1, 1, 1);}
.link_faded { color: #444;}
.link_faded:hover,.link_faded:focus { color: #5c5edc;}
.link_page.link_faded { font-size: 0.65rem;}
.link--social { font-size: 1.5rem; margin: 0 0.75rem;}
.text-hidden {
  position: absolute;
  display: block;
  overflow: hidden;
  width: 0;
  height: 0;
  color: transparent;
}
@media screen and (max-width: 60rem) {

  .pages-nav_item {
    width: 50%;
    min-height: 20px;
  }
  .link_page {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
  }
  .link{
    font-size: 1rem;
  }
  .link_page.link_faded {
    font-size: 0.85rem;
  }
}
@media screen and (max-width: 40rem) {
   .pages-nav {
    display: block;
    text-align: left;
  }
  .pages-nav_item {
    width: 100%;
    padding: 4px 0;
  }
  .menu-button {
    top: 15px;
    right: 10px;
    left: auto;
  }
}

 

At last add below code in App.js file for transition routing.

import React, { Component } from 'react';
import { Route, BrowserRouter as Router, Switch } from "react-router-dom";
import { TransitionGroup, CSSTransition } from "react-transition-group";
import Home from "./Home";
import Subpage from "./Subpage";
import Nav from './Nav';
import Page from './Page';
import './App.css';

class App extends Component {
  constructor() {
    super();
    this.state = {
      active: false
    };
  }

  menuClicked = () => {
    this.setState({
      active: !this.state.active
    })
  }

  render() {

    return (
      <Router>
        <div className="App">

          <button className={this.state.active ? "menu-button menu-button_open" : "menu-button"} onClick={this.menuClicked}>
            <span>Menu</span>
          </button>

          <Nav active={this.state.active} />

          <div className={this.state.active ? "pages-stack pages-stack_open" : "pages-stack"}>

            <div className={this.state.active ? "page page-inactive page-inactive_open" : "page page-inactive page-inactive_close"}></div>
            <div className={this.state.active ? "page page-inactive2 page-inactive2_open" : "page page-inactive2 page-inactive2_close"}></div>

            <div>
              <Route
                render={({ location }) => {
                  const { pathname } = location;                  
                  console.log(pathname);
                  return (
                    <TransitionGroup>
                      <CSSTransition
                        key={pathname}
                        classNames="fade"
                        timeout={{
                          enter: 300,
                          exit: 300,
                        }}
                      >
                        <Route
                          location={location}
                          render={() => (
                            <Switch>
                              <Route exact path="/" render={props => (
                                <Home
                                  {...props}
                                  active={this.state.active}
                                />
                              )} />
                              <Route exact path="/subpage" render={props => (
                                <Subpage
                                  {...props}
                                  active={this.state.active}
                                />
                              )} />
                              <Route path="/page" render={props => (
                                <Page
                                  {...props}
                                  active={this.state.active}
                                />
                              )} />
                            </Switch>
                          )}
                        />
                      </CSSTransition>
                    </TransitionGroup>
                  );
                }}
              />
            </div>
          </div>
        </div>
      </Router>
    );
  }
}

export default App;

That’s it! Now check your Output

Mayuri Lad

Front-end-developer as creative and programming skills to design, build and improve websites, having 4+ years of experience with understanding user experience and able to build websites that are easy to understand, navigate, and use, and adhere to design standards and specifications.

Recent Posts

Testing hk

Testing

2 years ago

Create and Used PIPE in angular

In this article, we have to show Create and Used PIPE in angular

2 years ago

Operation

Testing

2 years ago

Create and Used PIPE in angular

In this article, we have to show Create and Used PIPE in angular

2 years ago

Create and Used PIPE in angular

In this article, we have to show Create and Used PIPE in angular

2 years ago

TETS NEW

test

3 years ago