⭐️ css로 모달창 만들기 ⭐️
👍🏻 참고한 블로그
1) 부모 컴포넌트에서 isOpen
state로 모달창 열고 닫힘 상태관리
false
(모달창 안열려있으니까 - display: none
)true
로 바뀌면서 모달창 열림(display: block
)2) 모달 컴포넌트 조건부 display
(open, close의 원리)
isOpen이 true이면 display: block
-> open 했을 때 모달창 보여지게 만듦
isOpen이 false이면 display: none
-> 닫았을 때 모달창 안보이게 만듦
3) 모달창의 css
z-index
)는 메인화면 < 모달 배경색 < 모달창
메인화면은 연하게 만들면서 모달창이 열리는듯한 착시(?)를 주는 것이다!!
4) 모달 컴포넌트 닫으려면
🖥️ 모달창 코드 예시
// ✅ Header.jsx (헤더의 로그인 버튼 클릭 시 모달창 열기)
import Modal from '../Login/Modal';
const Header () => {
// isOpen이 true이면 - 모달창 display: block
// false이면 - 모달창 display: none
const [isOpen, setIsOpen] = useState(false);
// isSignUp이 true이면 회원가입 컴포넌트 열기
const [isSignUp, setIsSignUp] = useState(false);
// isLoggedIn이 trued이면 로그인 상태
const [isLoggedIn, setIsLoggedIn] = useState(false);
const onModalHandler = () => {
if (user.userId) {
setIsLoggedIn(false);
alert('로그아웃 되었습니다.');
} else {
setIsOpen(!isOpen);
if (isSignUp === true) {
setIsSignUp(!isSignUp);
}
}
};
return (
// ...생략
<StHeaderBtn onClick={onModalHandler}>Login</StHeaderBtn>
// ...생략
)
}
// ✅ Modal.jsx (모달창 - 로그인 시 Login, 회원가입 시 SignUp 컴포넌트 열기)
import Login from './Login';
import SignUp from './SignUp';
import * as St from './styles/Login.style';
const Modal = () => {
const onSignUpHandler = () => {
setIsSignUp(!isSignUp);
};
return (
<St.Background $isOpen={isOpen}>
<St.Container>
{isSignUp ? <SignUp/> : <Login/>}
</St.Container>
</St.Background>
);
};
export default Modal;
// ✅ css (styled-components)
export const Background = styled.div`
display: ${(props) => (props.$isOpen ? 'block' : 'none')};
z-index: 10;
background-color: rgba(0, 0, 0, 0.3);
width: 100%;
height: 100vh;
position: fixed;
top: 0;
left: 0;
`;
export const Container = styled.div`
z-index: 100;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: white;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 10px;
box-sizing: border-box;
width: 26%;
min-width: 400px;
height: 67%;
min-height: 500px;
border-radius: 5px;
`;
// ✅ Login.jsx (로그인 모달창)
// 눈모양 아이콘 react icons에서 import
import { FiEye, FiEyeOff } from 'react-icons/fi';
const Login = ({onSignUpHandler}) => {
// 회원가입 클릭시 회원가입 모달창으로 이동 (Header에서 props로 받음)
const onSignUpHandler = () => {
setIsSignUp(!isSignUp);
};
return (
<>
<St.LoginWrapper>
<St.CloseBtn onClick={onModalHandler}>x</St.CloseBtn>
<St.LogoName>Travel Vibe</St.LogoName>
<St.LoginTitle>로그인</St.LoginTitle>
<St.IdPwWrapper>
<St.InputContainer>
<St.LoginInput
placeholder='이메일'
value={email}
onChange={onCheckValidEmail}
/>
</St.InputContainer>
<StErrorMsg>
{!isValidEmail && email.length > 0 && (
<div>올바르지 않은 이메일 형식입니다.</div>
)}
</StErrorMsg>
<St.InputContainer>
<St.LoginInput
type={isShowPw ? 'text' : 'password'} // ⭐️⭐️ 아이콘 클릭시 input type 변경
autoComplete='on'
placeholder='비밀번호'
value={pw}
onChange={onCheckValidPw}
/>
<St.PwIcon onClick={onShowPw}>
{isShowPw ? <FiEye /> : <FiEyeOff />} // ⭐️⭐️ 비밀번호 표시/숨기기 아이콘
</St.PwIcon>
</St.InputContainer>
<StErrorMsg>
{!isValidPw && pw.length > 0 && (
<div>영문, 숫자 포함 8자 이상 입력해주세요.</div>
)}
</StErrorMsg>
</St.IdPwWrapper>
<St.MemoWrapper>
<St.CheckBox type='checkbox' />
<St.MemoInfo>로그인 유지하기</St.MemoInfo>
</St.MemoWrapper>
<St.LoginBtn onClick={onLoginConfirm}>로그인</St.LoginBtn>
<St.AskSignUpWrapper>
<St.AskSignUp>아직 회원이 아니신가요?</St.AskSignUp>
<St.SignUp onClick={onSignUpHandler}>회원가입</St.SignUp>
</St.AskSignUpWrapper>
</St.LoginWrapper>
</>
);
};
export default Login;
// ✅ css(styled-components)
// 모달창 닫기 버튼
export const CloseBtn = styled.button`
position: absolute;
width: 20px;
height: 20px;
top: 3%;
right: 3%;
padding: 0px;
background-color: white;
border: 1.5px solid ${colors.mainBlue};
border-radius: 3px;
color: ${colors.mainBlue};
cursor: pointer;
`;
export const PwIcon = styled.div`
position: absolute;
width: 30px;
top: 10%;
right: 1%;
cursor: pointer;
`;
npm install react-icons --save // npm
yarn add react-icons // yarn
manifest syntax error
manifest.json:1 Manifest: Line: 1, column: 1, Syntax error.
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
=> <link rel="/manifest" href="%PUBLIC_URL%/manifest.json" />
// '/'추가
input type password 에러
에러메시지 : [DOM] Input elements should have autocomplete attributes (suggested: "current-password"):
해결
<StLoginInput type='password' />
=> <StLoginInput type='password' autoComplete='on' />