To further understand React I have created a project using react-router-dom
, styled-components
and framer-motion
.
My versions are like so.
package-json:
....
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-icons": "^4.7.1",
"react-router-dom": "^6.8.1",
"react-scripts": "5.0.1",
"styled-components": "^5.3.6",
....
My modal has a simple animation with opacity and the container has backdrop-filter: blur(10px)
applied to it. I want the blur effect to be applied as soon as the fading in of the modal starts. As it is now, the animation is carried out and only after is the backdrop-filter applied. I find this strange, as all other styles, such as background-color
, are applied from the moment the animation starts.
My component Modal.js
:
import { IntroModal, ModalContainer } from './Modal.styled';
import { useEffect, useRef } from 'react';
import { motion } from 'framer-motion';
import { AnimatePresence } from 'framer-motion';
import { IoMdClose } from 'react-icons/io';
const Modal = ({ isOpen, toggleModal, closeOnOutsideClick, children }) => {
const modalRef = useRef(null);
useEffect(() => {
const handleClickOutside = (event) => {
if (
closeOnOutsideClick &&
modalRef.current &&
!modalRef.current.contains(event.target)
) {
toggleModal();
}
};
document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, [modalRef, closeOnOutsideClick, toggleModal]);
const closeButtonStyle = {
color: 'white',
fontSize: '1.5rem',
cursor: 'pointer',
filter: 'drop-shadow(0px 0px 2px #000)',
};
!isOpen
? (document.body.style.overflow = 'hidden')
: (document.body.style.overflow = 'auto');
return (
<AnimatePresence>
!isOpen && (
<motion.div
style={isOpen ? { display: 'none' } : null}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
key={isOpen}
>
<IntroModal>
<ModalContainer ref={modalRef}>
<button onClick={toggleModal}>
<IoMdClose style={closeButtonStyle} />
</button>
{children}
</ModalContainer>
</IntroModal>
</motion.div>
)
</AnimatePresence>
);
};
export default Modal;
Modal.styled.js
:
import styled from 'styled-components';
export const IntroModal = styled.div`
position: fixed;
display: flex;
justify-content: center;
align-items: center;
z-index: 11;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.7);
button {
position: absolute;
top: 0.3rem;
right: 0.3rem;
padding: 0.5rem;
border: none;
background: transparent;
transition: transform 0.2s ease-in-out;
&:hover {
transform: scale(1.1);
}
}
img {
width: 50%;
box-shadow: 0 0 15px #000;
margin-top: 1rem;
}
p {
font-weight: bold;
font-size: 1rem;
padding: 0 1rem;
}
`;
export const ModalContainer = styled.div`
backdrop-filter: blur(10px);
position: absolute;
top: 50%;
width: 30%;
background-color: rgba(38, 50, 50, 0.5);
text-align: center;
transform: translateY(-50%);
padding: 1rem 0.2rem 0.5rem;
border-top: 0.7px solid #b6b6b666;
border-right: 0.7px solid #8e8e8e66;
border-bottom: 0.7px solid #000;
border-left: 0.7px solid #77777766;
border-radius: 18px;
box-shadow: 0 0 1rem 0 #000;
min-height: 200px;
display: inherit;
flex-wrap: wrap;
flex-direction: row;
justify-content: center;
align-items: center;
@media screen and (max-width: 768px) {
width: 80vw;
height: 80vh;
}
`;
export const ModalWrapper = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 50%;
height: 25%;
font-size: 2rem;
`;
Here is a gif of the appearance of it now:
I have tried to apply the styles directly to the component, eg style={backdropFilter: blur(10px)
, and also including it in the animation like so (tried both in outer motion.div
and ModalContainer
separately):
<motion.div
style={isOpen ? { display: 'none' } : null}
initial={{ opacity: 0, backdropFilter: 'blur(0px)' }}
animate={{ opacity: 1, backdropFilter: 'blur(10px)' }}
exit={{ opacity: 0, backdropFilter: 'blur(0px)' }}
key={isOpen}
>
<IntroModal>
<motion.ModalContainer ref={modalRef}
initial={{ opacity: 0, backdropFilter: 'blur(0px)' }}
animate={{ opacity: 1, backdropFilter: 'blur(10px)' }}
exit={{ opacity: 0, backdropFilter: 'blur(0px)' }}
key={isOpen}
>
<button onClick={toggleModal}>
<IoMdClose style={closeButtonStyle} />
</button>
{children}
</motion.ModalContainer>
</IntroModal>
</motion.div>
Any tips and advice much appreciated!