In my react-js project i have created a sign up form:
SignUpPage.js
const SignUpPage = () => {
// Password Toggle hook
const [PasswordInputType, PasswordToggleIcon] = usePasswordToggle();
const [ConfirmPasswordInputType, ConfirmPasswordToggleIcon] = usePasswordToggle();
const initialValues = {
firstname: '',
lastname: '',
username: '',
email: '',
password: '',
confirm_password: '',
usage_date: ''
}
const [formValues, setFormValues] = useState(initialValues);
const [formErrors, setFormErrors] = useState({});
const [isSubmit, setIsSubmit] = useState(false);
const handleChange = (e) => {
const { name, value } = e.target;
setFormValues({ ...formValues, [name]: value });
};
const handleSubmit = (e) => {
e.preventDefault();
setFormErrors(valildate(formValues));
setIsSubmit(true)
};
const valildate = (values) => {
const errors = {};
const regex = /^[^s@]+@[^s@]+.[^s@]{2,}$/i
const valildateEmail = (email) => {
if (regex.test(values.email)) {
return true
} else {
return false
}
}
if (!values.firstname) {
errors.firstname = "First Name is required!";
}
if (!values.lastname) {
errors.lastname = "Last Name is required!";
}
if (!values.username) {
errors.username = "Username is required!";
}
if (!values.email) {
errors.email = "Email is required!";
}
const valid = valildateEmail(values.email)
if (values.email && !valid) {
errors.email = "Invalid Email!";
}
if (!values.password) {
errors.password = "Password is required!"
}
if (!values.confirm_password) {
errors.confirm_password = "Confirm Password is required!"
}
if (values.password !== values.confirm_password) {
errors.confirm_password = "Passwords don't match!"
}
return errors
};
return (
<div>
{ <Helmet>
<link rel='stylesheet' href='css/SignUpPage.css' />
</Helmet> }
<NavigateToHome authTokens={authTokens} />
<div className='container'>
<div className='content'>
<div className='user-details'>
<form onSubmit={handleSubmit}>
<header>SignUp</header>
<div className='column'>
<div className='input-box'>
<label>First Name</label>
<input type='text'
name='firstname'
placeholder='First Name'
onChange={handleChange}
{...(formErrors.firstname ? {error: 'true'} : {error: 'false'})}
/>
{formErrors.firstname && (
<span className='error username-error'>
<BiErrorCircle className='error-icon' />
<p className='error-text'>{formErrors.firstname}</p>
</span>
)}
</div>
<div className='input-box'>
<label>Last Name</label>
<input type='text'
name='lastname'
placeholder='Last Name'
onChange={handleChange}
{...(formErrors.lastname ? {error: 'true'} : {error: 'false'})}
/>
{formErrors.lastname && (
<span className='error lastname-error'>
<BiErrorCircle className='error-icon' />
<p className='error-text'>{formErrors.lastname}</p>
</span>
)}
</div>
</div>
<div className='input-box'>
<label>Username</label>
<input
type='text'
name='username'
placeholder='Username'
onChange={handleChange}
{...(formErrors.username ? {error: 'true'} : {error: 'false'})}
/>
{formErrors.username && (
<span className='error username-error'>
<BiErrorCircle className='error-icon' />
<p className='error-text'>{formErrors.username}</p>
</span>
)}
</div>
<div className='input-box'>
<label>Email</label>
<input type='text'
name='email'
placeholder='Email'
onChange={handleChange}
{...(formErrors.email ? {error: 'true'} : {error: 'false'})}
/>
{formErrors.email && (
<span className='error email-error'>
<BiErrorCircle className='error-icon' />
<p className='error-text'>{formErrors.email}</p>
</span>
)}
</div>
<div className='column'>
<div className='input-box'>
<label>Password</label>
<input
type={PasswordInputType}
name='password'
placeholder='Password'
onChange={handleChange}
{...(formErrors.password ? {error: 'true'} : {error: 'false'})}
/>
{formErrors.password && (
<span className='error password-error'>
<BiErrorCircle className='error-icon' />
<p className='error-text'>{formErrors.password}</p>
</span>
)}
<span className='password-toggle-icon'>{PasswordToggleIcon}</span>
</div>
<div className='input-box'>
<label>Confirm Password</label>
<input
type={ConfirmPasswordInputType}
name='confirm_password'
placeholder='Confirm Password'
onChange={handleChange}
{...(formErrors.confirm_password ? {error: 'true'} : {error: 'false'})}
/>
{formErrors.confirm_password && (
<span className='error confirm-password-error'>
<BiErrorCircle className='error-icon' />
<p className='error-text'>{formErrors.confirm_password}</p>
</span>
)}
<span className='confirm-password-toggle-icon'>{ConfirmPasswordToggleIcon}</span>
</div>
</div>
<div className='input-box'>
<label className='details'>Expiration Date</label>
<input type='date' name='usage_date' onChange={handleChange}/>
</div>
<div className='button'>
<button type='submit'>Signup</button>
</div>
<div className='link'>
<span>Already have an account? <Link className='login-link' to={'/login'}>LogIn</Link></span>
</div>
</form>
</div>
</div>
</div>
</div>
);
}
export default SignUpPage
SignUpPage.css
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600&display=swap');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Poppins', sans-serif;
}
body {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
background-color: lightgrey;
}
.container {
position: relative;
max-width: 700px;
width: 100%;
background: white;
padding: 25px;
border-radius: 6px;
box-shadow: 0 0px 15px rgba(0, 0, 0, 0.1);
}
.container header {
font-size: 28px;
font-weight: 600;
color: #232836;
text-align: center;
}
.user-details form {
margin-top: 30px;
}
form .input-box {
width: 100%;
margin-top: 20px;
}
.input-box label {
color: #232836;
}
form :where(.input-box input) {
position: relative;
height: 50px;
width: 100%;
outline: none;
font-size: 16px;
margin-top: 8px;
border: 1px solid #CACACA;
border-radius: 6px;
padding: 0 15px;
}
.input-box input:focus {
border-bottom-width: 2px;
}
form .column {
display: flex;
column-gap: 15px;
}
form button {
height: 50px;
width: 100%;
border: none;
font-size: 16px;
font-weight: 400;
border-radius: 6px;
color: #fff;
background-color: #0171d3;
transition: all 0.3s ease;
cursor: pointer;
margin-top: 30px;
}
form button:hover {
background-color: #016dcb;
}
.link {
text-align: center;
margin-top: 10px;
}
.link a,
.link span {
font-size: 14px;
font-weight: 400;
color: #232836;
}
.link a {
color: #0171d3;
text-decoration: none;
}
.password-toggle-icon {
position: relative;
font-size: 18px;
color: #8b8b8b;
cursor: pointer;
bottom: 35px;
left: 90%;
transform: translateY(50%);
}
.confirm-password-toggle-icon {
position: relative;
font-size: 18px;
color: #8b8b8b;
cursor: pointer;
bottom: 35px;
left: 90%;
transform: translateY(50%);
}
.error {
display: flex;
align-items: center;
margin-top: 6px;
color: red;
font-size: 13px;
}
.error .error-icon {
margin-right: 6px;
font-size: 15px;
}
.error .error-text {
align-items: flex-start;
}
.input-box input[error="true"] {
border: 1px solid red;
}
usePasswordToggle.js
import React, { useState } from 'react'
import { BiHide, BiShow } from 'react-icons/bi'
const usePasswordToggle = () => {
const [visible, setVisibility] = useState(false)
const Icon = (
visible
? <BiHide onClick={() => setVisibility(!visible)} />
: <BiShow onClick={() => setVisibility(!visible)}/>
);
const InputType = visible ? 'text' : 'password';
return [InputType, Icon];
}
export default usePasswordToggle
When loading the page the form looks like this:
My problem is that when a user tries to submit an empty form the validator is called and the form looks like this:
How can i make the show password icon remain in the same position as before when the user submits an empty form?
I played with the settings inside the SignUpPage.css without any luck and also tried to hard-code the position but still the icon changes position when the user submits an empty form.
2
Answers
Because your password
input
and theerror message
are in same level.So group
input
andshowing password icon
into one level different fromerror message
, like below.I think it’ll work as you wish.
why it is so rough ? you should create label and input components and use it again and again , in every form of the application . like this
and in the form
i hope this will solve your problem