skip to Main Content

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:

SignUp form before

My problem is that when a user tries to submit an empty form the validator is called and the form looks like this:

SignUp form after

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


  1. Because your password input and the error message are in same level.

    So group input and showing password icon into one level different from error message, like below.

    <div className="input-box">
      <label>Password</label>
      <div>
        <input
          type={PasswordInputType}
          name="password"
          placeholder="Password"
          onChange={handleChange}
          {...(formErrors.password ? { error: "true" } : { error: "false" })}
        />
        <span className="password-toggle-icon">{PasswordToggleIcon}</span>
      </div>
    
      {formErrors.password && (
        <span className="error password-error">
          <BiErrorCircle className="error-icon" />
          <p className="error-text">{formErrors.password}</p>
        </span>
      )}
    </div>;
    

    I think it’ll work as you wish.

    Login or Signup to reply.
  2. 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

    type LabelProps = {
      label: string;
      className?: string;
    };
    export const FormLabel = ({ label, className }: LabelProps) => {
      return (
        <label htmlFor={label} className={className ? className : ""}>
          {label}
        </label>
      );
    };
    type InputProps = {
      type: string;
      name: string;
      onChange: (event: ChangeEvent<HTMLInputElement>) => void;
      className?: string;
      value: string;
      placeholder: string;
      maxLength?: number;
    };
    export const FormInput = ({
      name,
      type,
      onChange,
      className,
      value,
      placeholder,
      maxLength,
    }: InputProps) => {
      return (
        <input
          name={name}
          type={type}
          value={value}
          onChange={onChange}
          className={className ? className : ""}
          placeholder={placeholder}
          maxLength={maxLength}
        />
      );
    };
    

    and in the form

       export const LoginForm = () => {
          const [showPassword, setShowPassword] = useState(false);
    
     <FormLabel
                  label={`Password`}
                  className={`flex text-sm  opacity-0 group-focus-within:opacity-100 `}
                />
                <span
                  className={`cursor-pointer right-10 top-9 text-xl absolute `}
                  onClick={() => setShowPassword(!showPassword)}
                >
                  {!showPassword ? (
                    <HideEyeIcon size={"32"} />
                  ) : (
                    <VisibleEye size={"32"} />
                  )}
                </span>
                <FormInput
                  name="password"
                  value={signUpData.password}
                  type={`${showPassword ? "text" : "password"}`}
                  placeholder={`password`}
                  onChange={(e) => handleChange(e)}
                  className={inputStyles}
                />
              </div>
    

    i hope this will solve your problem

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search