Fading a component in and fading another one out React.js - javascript

I just recently started getting into using React.js and to make it easier for myself I'm trying to recreate projects I've made in the past, but instead of using jQuery like I did in the past I'm completely avoiding jQuery and using only React.
I tend to do animations where a div would fade in as another fades out like this:
$("#start").click(function() {
$("#h1").fadeOut(750);
$("#h2").delay(500).fadeIn(750);
$("#h1").css("z-index", 0);
$("#h2").css("z-index", 1);
});
I was wondering how can I reproduce this fade in and out effect without jQuery
(I know CSS animations could change the opacity, but the opacity isn't the only thing I'm trying to change, this affects the display property as well).

A simple way is to use CSS transitions. Basically you just add a class to an element, and define a transition in the CSS and it does the rest for you
There is a tutorial here
https://www.w3schools.com/css/css3_transitions.asp
Which does a good job of explaining how it all works with examples and a playground for you to try your own

The CSS Transition group add-on might help, it let's you define transitions like this:
JS:
<ReactCSSTransitionGroup
transitionName="example"
transitionEnterTimeout={500}
transitionLeaveTimeout={300}>
{items}
</ReactCSSTransitionGroup>
CSS:
.example-enter {
opacity: 0.01;
}
.example-enter.example-enter-active {
opacity: 1;
transition: opacity 500ms ease-in;
}
.example-leave {
opacity: 1;
}
.example-leave.example-leave-active {
opacity: 0.01;
transition: opacity 300ms ease-in;
}

One option would be to use a framework, like react-bootstrap, which includes a lot of the UI components you need for any given project. It includes a Fade component. Documentation can be found here: https://react-bootstrap.github.io/components.html#utilities
class Example extends React.Component {
constructor(...args) {
super(...args);
this.state = {};
}
render() {
return (
<div>
<Button onClick={()=> this.setState({ open: !this.state.open })}>
click
</Button>
<Fade in={this.state.open}>
<div>
<Well>
THIS CONTENT WILL FADE
</Well>
</div>
</Fade>
</div>
);
}
}
ReactDOM.render(<Example/>, mountNode);

Related

CSS Animation with Vue.js

I'm learning Vue Js.
Actualy I'm making a chat example application with SCSS and Vue Js.
On my project I've decided to set some CSS animations to the messages box.
Here is the snippet of the animation code:
SCSS:
.push {
...
animation-duration: 0.3s;
animation-timing-function: linear;
animation-fill-mode: forwards;
&.received {
...
animation-name: inFromLeft;
}
&.sent {
...
animation-name: inFromRight;
}
}
#keyframes inFromRight {
0% {
right: -100%;
}
100% {
right: 0;
}
}
#keyframes inFromLeft {
0% {
left: -100%;
}
100% {
left: 0;
}
}
HTML / VUE:
<div id="chat">
<div v-for="(message, index) in messages" :key="index" class="push" :class="type(message)">
...
</div>
</div>
All the message are stored in the users object in array(s) format. (with vue data).
The problem is that some messages use the animation and some messages not.
I think this problem is related to vue and his method to load array(s).
Here is a dimostration of the final result:
https://www.youtube.com/watch?v=EYsBk4HboD8
Can someone help me to understand the problem and how to fix?
(I prefer use CSS animations and avoid to use the vue transition at the moment).
Thank you!
The problem is in :key="index", changing the key to be unique per-message. should fix the issue
Explanation: Vue tracks every unique element in the loop through keys to avoid removing and re-rendering elements unless they really got changed, setting messages keys as their index makes Vue think that no new element was added if element in index 3 was removed and a new element was added with the same key
read more about this here https://v2.vuejs.org/v2/guide/list.html#Array-Change-Detection

Can't animate modal on ReactJS

I'm currently creating my custom implementation of a modal. All works perfectly fine so far but I can't seem to animate it and I can't get my head around it.
This is my Modal component
import React from 'react'
import Slider from './Slider'
import {IoIosCloseCircleOutline} from "react-icons/io"
import styled from "styled-components";
export default function Modal(props) {
const Modal = styled.div `
transform: translateX(${({animateSlideInRight}) => (animateSlideInRight ? "0" : "100vw")});
transition: transform 1s;
width: 1000px;
height: 650px;
z-index: 100;
position: fixed;
background: white;
transition: all 1.1s ease-out;
box-shadow:
-2rem 2rem 2rem rgba(black, 0.2);
visibility: visible;
display: flex;
border-bottom-right-radius: 100px;
`
const closeModal = () => {
props.setShow(false)
}
const data = props.data
if (!props.show) {
return null
}
return (
<div className="modalWrapper">
<Modal className="modal" id="modal" animateSlideInRight = {props.show}>
<div className="modalHeaderWrapper">
<IoIosCloseCircleOutline className="modalCloseCross" onClick={closeModal}/>
<img src={data[0].logo} alt="logo" />
<h2>{data[0].title}</h2>
</div>
<div className="modalRightFlex">
<Slider
images={[data[0].image1Carrousel, data[0].image2Carrousel, data[0].image3Carrousel]}
/>
<div className="modalRightDescription">
<h1>Description</h1>
<p>{data[0].description}</p>
<h1>Technologies</h1>
<div className="modalTechnologiesWrapper">
{data[0].technologiesUsed.map((image) => {
return <img src={image}/>
})}
</div>
</div>
</div>
</Modal>
</div>
)
}
As you see my modal is a styledComponent that defines whether to translate in X or not depending on the show state. In my scenario I had to lift up state since I'm opening this modal from clicking on a card which in itself is a different component, so their ancestor is taking care of the states.
My current CSS for modal is as seen in the styled div.
Things I have tried
1-tried having a regular div and handle the animation through CSS with keyframes --> It works for sliding in but it doesn't when I close (in that instance I had my show state defining a class name for the modal with a different animation for each of them)
2-tried to set a animate state and define the className based on whether that state is true or false. It works the first time when I close (despite having to introduce a timeout of the animation duration between setting animate to false and show to false) but then it goes bonkers and starts flickering everywhere.
Anyway someone can see the issue? Many thanks
edit
Sanbox link: https://codesandbox.io/s/trusting-shape-vxujw
You should define Modal in the outer scope of the component rendering it, the animation does not complete and you resetting it by redefining it on the next render.
Also resetting an animation should be done with none instead of giving an actual length.
Moreover, there might be more CSS bugs related that can hide your modal animation like z-index and position, if your question is focused on an animation problem you should remove all the noise around it.
See working example:
const Animation = styled.div`
transform: ${({ animate }) => (animate ? "none" : "translateX(500px)")};
transition: transform 1s;
`;
function Modal(props) {
return <Animation animate={props.show}>hello</Animation>;
}
function Component() {
const [show, toggle] = useReducer((p) => !p, false);
return (
<>
<Modal show={show} />
<button onClick={toggle}>show</button>
</>
);
}
Also, you shouldn't return null when you don't want to animate, you will lose the close animation.
// remove this code
if (!props.show) {
return null;
}

React How to remove the animation of Material-UI Select

I'm using the React Material UI's Select Component. I wish to remove or speeden the animation that comes when the menu is opening. I tried something like:
<Select
...
TransitionComponent={({children}) => children}
>
<MenuItem value={...}>...</MenuItem>
...
</Select>
But this is not working, please help
add this to your stylesheet:
.MuiMenu-paper {
transition-duration: 0s !important;
}
This basically overrides the transition duration of the select dropdown and sets it to 0 seconds.
You can also change the duration according to what you like (make it faster). The default animation duration is:
transition-duration: 251ms, 167ms;
The reason why it doesn't work:
MUI <Select /> API don't have props TransitionComponent, as well as some other components like <Tooltip /> do have
Refer: API document of
MUI Tooltip
MUI Select
Related QA: React Material UI Tooltips Disable Animation
Solution
Override the transition style would be fine.
div.MuiPaper-root {
transition: none !important;
}
Explanation
The HTML structure for options:
Since it's been dynamically generated outside the main component, it's not suitable for us to directly set styles for them.
However, we can optionally override the styles by those classNames like MuiPaper-root, or some other ways like a given id.
<div
class="MuiPaper-root MuiMenu-paper MuiPopover-paper MuiPaper-elevation8 MuiPaper-rounded"
tabindex="-1"
style="opacity: 1; transform: none; min-width: 40px; transition: opacity 251ms cubic-bezier(0.4, 0, 0.2, 1) 0ms, transform 167ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; top: 16px; left: 16px; transform-origin: -8px 7.7px;"
>
<ul
class="MuiList-root MuiMenu-list MuiList-padding"
role="listbox"
tabindex="-1"
>
...
</ul>
</div>;
To add to keikai's answer, you can also do this globally with a theme change:
const theme = createMuiTheme({
overrides: {
MuiPaper: {
root: {
transition: 'none !important'
},
},
}
});
For those that are using a corresponding Material UI InputLabel component with a mui Select component, I was able to pass in the following props to the InputLabel component to disable the animation and shrink altogether:
<div>
<FormControl>
<InputLabel
disableAnimation={true}
shrink={false}
...
>
{`some label`}
</InputLabel>
<Select>
{`...`}
</Select>
</FormControl>
</div>
MUI Input Label API

Render a component after a timeout through pure CSS

I'm aware that there is a way to achieve the effect of a component being rendered after a given timeout but I would like to do it in pure CSS through transitions. The problem is that when looking at tutorials for using css transitions - you usually have to hover over the element in order to trigger the animation - but in my case - I simply want the element to become visible after 2 seconds from being rendered. How can I achieve this?
animation can help :
p {
opacity:0;
animation:show 5s 2s forwards;
}
#keyframes show {
to {opacity:1}
}
<p>see me</p>
See https://developer.mozilla.org/en-US/docs/Web/CSS/animation-fill-mode
The animation-fill-mode CSS property specifies how a CSS animation should apply styles to its target before and after its execution.
A simple component is in this CodePen. You can simply apply the css animation on opacity.
var SomeComponent = React.createClass({
render: function() {
return (
<div className="myClass">My Component</div>
);
}
});
React.render(
<SomeComponent />,
document.getElementById('root'));
.myClass {
opacity:0;
animation:show 2s 1s forwards;
}
#keyframes show {
to {
opacity:1
}
}
<div id="root"></div>

Opacity transition works on fade out, but not fade in

This is frustrating me to no end. Before I post the code, here's a summary:
The goal, in simple terms: when I double click X, I want it to fade out; when I click Y, I want X to fade in.
The method: I'm using CSS to create the actual fade-in and fade-out "animations." I'm using JavaScript to apply the classes when necessary using a little trickery.
The problem: the fade-in transition doesn't work -- the element just appears instantly. What is driving me insane is the fact that the fade-in, when instantly added back onto a faded-out object, works perfectly. I'll explain this better as a comment in the JS code.
(Yes, I've added opacity: 1 and transition: opacity onto the base elements. It had no effect at all.)
The code:
CSS
*.fade-out {
opacity: 0;
transition: opacity 400ms;
}
*.fade-in {
opacity: 1;
transition: opacity 400ms;
}
*.hide {
display: none;
visibility: hidden;
}
JavaScript
$( '#ArtistEmblem' ).on( 'dblclick', function() {
fadeOut($( '#ArtistEmblem' ));
fadeIn($( '#btnShowLogo' ));
});
$( '#btnShowLogo' ).on( 'click', function() {
fadeOut($( '#btnShowLogo' ));
fadeIn($( '#ArtistEmblem' ));
});
function fadeOut(element) {
element.addClass( 'fade-out' );
setTimeout( function () {
element.addClass( 'hide' );
/*
* I tried immediately adding the 'fade-in' class here
* and it worked -- as soon as the element faded out, it faded
* back in (using the CSS transition). However, outside of this,
* it REFUSES to work; everything appears instantly
*/
console.log('timer triggered');
}, 400);
}
function fadeIn(element) {
element.removeClass( 'hide' );
element.removeClass( 'fade-out' );
element.addClass( 'fade-in' );
}
Relevant HTML
<div id="ArtistEmblem">
<img src="img/logo_artist_2.png" />
</div>
<div id="PopMenu" class="collapse">
<article>
<header>
<b>Debug Menu</b>
</header>
<section>
<button id="btnOpenOverlay">Open Overlay</button>
<button id="btnShowLogo" class="hide">Show Logo</button>
<button id="btnClose">Close Menu</button>
</section>
</article>
</div>
I apologize if this is something obvious but I've wasted far too much time trying to solve it. I am also open to better, faster, or more efficient solutions if that would be the best answer. Thanks in advance!
The problem is that the initial opacity of "hidden" element is 1 by default. You just need to set it to 0. And also remove display: none –
*.hide {
opacity: 0;
}
Also I would do a little refactoring and remove setTimeout:
$('#ArtistEmblem').on('click', function() {
fade($('#btnShowLogo'), $(this));
});
$('#btnShowLogo').on('click', function() {
fade($('#ArtistEmblem'), $(this));
});
function fade(inElement, outElement) {
inElement.removeClass('hide');
inElement.addClass('fade-in');
outElement.removeClass('fade-in');
outElement.addClass('fade-out');
}
If you don't want the hidden element to occupy space and you want it to be displayed-none, then you need to set display: block before starting the fadeOut.
I know you're asking for a JS heavy answer, but I highly recommend toggling a class of "active", "open" or something similar and using CSS with the transition. Less is more here.
Here's an example fiddle of something I've transitions not only the opacity, but also the z-index. That's the key with these transitions if you intend on having any elements below such as buttons that require hovering, clicking, etc.
JS Fiddle
Key parts:
.container {
z-index: -1;
opacity: 0;
transition: z-index .01s 1s, opacity 1s;
}
.container.active {
transition: z-index 0s, opacity 1s;
z-index: 500;
opacity: 1;
}
EDIT
I was just messing around with this type of thing for my own project, and observing how beautiful Stripe handles their navigation bar. Something so simple changes everything, and that's pointer-events. If you're okay with its support, (notable no ie. 10) this is infinitely easier to integrate. Here's another fiddle of the simulation in a nav bar.
The key part is pointer-events: none, as it ignores click events if set to none, almost as if it wasn't there, yet visibly it is. I highly recommend this.
https://jsfiddle.net/joshmoxey/dd2sts7d/1/
Here is an example using Javascript Animate API. Animate API is not supported in IE/Edge though.
var element = document.getElementById("fade-in-out")
var button = document.getElementById("x")
button.addEventListener("click", function(event) {
element.animate([{opacity: 1, visibility: "visible"},{opacity: 0, visibility: "hidden"}], {duration: 2000})
setTimeout(function() { element.remove() }, 2000)
})
button.addEventListener("dblclick", function(event) {
element && element.animate([{opacity: 0}, {opacity: 1}], {duration: 2000})
})
<input id="x" type="button" value="Click here" />
<div id="fade-in-out"> FADE ME </div>

Categories