React.js Hooks Random Password Generator and Manager UI with Icons in Browser Using Vanilla Javascript Full Project For Beginners

You are currently viewing React.js Hooks Random Password Generator and Manager UI with Icons in Browser Using Vanilla Javascript Full Project For Beginners

 

Welcome folks today in this blog post we will be building a random password generator in react.js using hooks in browser using vanilla javascript.All the full source code of the application is given below.

 

 

 

Get Started

 

 

 

In order to get started you need to make an index.html file and copy paste the following code

 

 

index.html

 

 

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css"/>
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>

 

 

 

Now make a style.css file and copy paste the following code

 

 

style.css

 

 

@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap');

/* Global CSS */
:root {
  --clr-dark: #101820;
  --clr-light: #eef2f6;
  --clr-accent: #fb9961;

  --ff-poppins: 'Poppins', sans-serif;

  --fs-logo: 6rem;
  --fs-h1: 4.5rem;
  --fs-h2: 3.5rem;
  --fs-h3: 2.5rem;
  --fs-h4: 1.5rem;
  --fs-h5: 1.125rem;
  --fs-body: 1rem;
  --fs-small: 0.9rem;
}

@media (max-width: 1600px) {
  :root {
    --fs-logo: 4.5rem;
    --fs-h1: 3rem;
    --fs-h2: 2rem;
    --fs-h3: 1.25rem;
    --fs-h4: 1rem;
    --fs-h5: 0.975rem;
    --fs-body: 0.875rem;
    --fs-small: 0.775rem;
  }
}

@media (max-width: 425px) {
  :root {
    --fs-logo: 2.7rem;
    --fs-h1: 2rem;
    --fs-h2: 1.8rem;
    --fs-h3: 1rem;
    --fs-h4: 0.8rem;
    --fs-h5: 0.775rem;
    --fs-body: 0.675rem;
    --fs-small: 0.575rem;
  }
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

body {
  margin: 0;
  padding: 0;
  line-height: 1.6;
  word-spacing: 1.4px;
  font-family: var(--ff-poppins);
  font-size: var(--fs-body);
  background-color: var(--clr-dark);
  color: var(--clr-light);
}

button {
  margin: 0;
  padding: 0;
  border: 0;
  outline: 0;
  display: inline-block;
  background: none;
  cursor: pointer;
  font-family: var(--ff-poppins);
  text-transform: capitalize;
}

a {
  margin: 0;
  padding: 0;
  border: 0;
  outline: 0;
  display: inline-block;
  background: none;
  cursor: pointer;
  font-family: var(--ff-poppins);
  text-transform: capitalize;
  text-decoration: none;
  color: inherit;
}

img {
  pointer-events: none;
  user-select: none;
}

ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

h1 {
  font-size: var(--fs-h1);
  font-family: var(--ff-poppins);
}

h2 {
  font-size: var(--fs-h2);
  font-family: var(--ff-poppins);
}

h3 {
  font-size: var(--fs-h3);
  font-family: var(--ff-poppins);
}

h4 {
  font-size: var(--fs-h4);
  font-family: var(--ff-poppins);
}

h5 {
  font-size: var(--fs-h5);
  font-family: var(--ff-poppins);
}

p {
  word-spacing: 1.4px;
  font-family: var(--ff-poppins);
  font-weight: 300;
}

.btn-bg {
  font-size: var(--fs-h5);
  font-weight: 700;
  text-decoration: none;
  padding: 1em 2.25em;
  color: var(--clr-dark);
  background-color: var(--clr-accent);
  border: 1px solid var(--clr-accent);
  transition: all 0.3s;
}

.btn-bg:hover,
.btn-bg:focus {
  background-color: var(--clr-light);
  border: 1px solid var(--clr-light);
}

.btn-border {
  font-size: var(--fs-h5);
  font-weight: 700;
  text-decoration: none;
  padding: 1em 2.25em;
  color: var(--clr-accent);
  background-color: transparent;
  border: 1px solid var(--clr-accent);
  transition: all 0.3s;
}

.btn-border:hover,
.btn-border:focus {
  background-color: rgba(251, 153, 97, 0.1);
}

.btn {
  font-size: var(--fs-body);
  font-weight: 400;
  text-decoration: none;
  color: var(--clr-light);
  background-color: transparent;
}

.menu-btn_border {
  font-size: var(--fs-small);
  font-weight: 400;
  text-decoration: none;
  padding: 1em 2.25em;
  min-width: 9em;
  color: var(--clr-light);
  background-color: transparent;
  border: 1px solid var(--clr-accent);
  transition: all 0.3s;
}

.menu-btn_border:hover,
.menu-btn_border:focus {
  background-color: rgba(50, 72, 95, 0.3);
}

.menu-btn_bg {
  font-size: var(--fs-small);
  font-weight: 400;
  text-decoration: none;
  padding: 1em 2.25em;
  min-width: 9em;
  color: var(--clr-light);
  background-color: var(--clr-accent);
  transition: all 0.3s;
}

.menu-btn_bg:hover,
.menu-btn_bg:focus {
  background-color: rgba(50, 72, 95, 0.8);
}

.lg-container {
  width: 90%;
  margin: 0 auto;
}

.md-container {
  width: 80%;
  margin: 0 auto;
}

.sm-container {
  width: 65%;
  margin: 0 auto;
}

.lg_section-spacing {
  margin-bottom: 25rem;
}

.section-spacing {
  margin-bottom: 20rem;
}

.md_section-spacing {
  margin-bottom: 10rem;
}

.smMD_section-spacing {
  margin-bottom: 7.5rem;
}

.sm_section-spacing {
  margin-bottom: 5rem;
}

.logo {
  font-size: var(--fs-logo);
}

/* Password Manager CSS */
.manager-parent {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.manager-title {
  text-align: center;
}

.key {
  font-size: var(--fs-h1);
  margin-top: var(--fs-h1);
  color: var(--color-light);
}

.lock-container {
  display: flex;
  justify-content: center;
  align-items: center;
}

.lock {
  font-size: var(--fs-h1);
  margin-top: var(--fs-h1);
  color: var(--color-light);
  opacity: 0.3;
}

.manager-form {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  margin-bottom: 2em;
}

@keyframes reveal {
  from {
    opacity: 0;
  }
  to {
    opacity: 0.7;
  }
}

.manager-form-label {
  opacity: 0.7;
  font-size: var(--fs-body);
  margin-bottom: var(--fs-body);
  text-align: center;
  color: var(--clr-accent);
  animation-name: reveal;
  animation-duration: 1s;
}

.manager-form-input-container {
  display: flex;
  justify-content: center;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: 2em;
  margin-bottom: 2em;
}

.manager-input {
  border: none;
  border-bottom: 1px solid var(--clr-accent);
  outline: none;
  background: transparent;
  width: 15em;
  font-size: var(--fs-h5);
  padding: 1em 0;
  color: var(--clr-light);
  align-self: flex-start;
}

.manager-ul {
  width: 30em;
}

.manager-ul-li-container {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.manager-ul-li-title {
  margin: 0;
  align-self: start;
  color: var(--clr-accent);
  text-transform: capitalize;
}

.hidden-password {
  border: none;
  outline: none;
  background: transparent;
  color: var(--clr-light);
  font-size: var(--fs-h5);
  width: 20em;
}

.manager-ul-li {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
  font-size: var(--fs-h5);
  margin-bottom: 1em;
}

.manager-li-icons {
  color: var(--clr-accent);
  font-size: var(--fs-h5);
  margin-left: 1em;
}

.manager-form-btn-container {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  gap: 2em;
}

 

 

 

And now make a script.js file and copy paste the following code

 

 

script.js

 

 

const { useState, useRef, useEffect } = React;
import {v4 as uuidv4} from "https://cdn.skypack.dev/uuid@8.3.2";

// Password Manager component
const PasswordManager = () => {
  const LOCAL_STORAGE = () =>
    JSON.parse(localStorage.getItem('Passwords')) || [];
  const [passwordItems, setPasswordItems] = useState(LOCAL_STORAGE);
  const [passwordLength, setPasswordLength] = useState('');
  const [passwordTitle, setPasswordTitle] = useState('');
  const [isEditing, setIsEditing] = useState(false);
  const [editId, setEditId] = useState('');
  const [editingPassword, setEditingPassword] = useState('');
  const inputPasswordRef = useRef(null);
  const inputTitleRef = useRef(null);

  const handlePasswordLengthChange = e => setPasswordLength(e.target.value);

  const handlePasswordTitleChange = e => setPasswordTitle(e.target.value);

  const generatePassword = () => {
    const length = passwordLength;
    const charset =
      'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    let retVal = '';
    for (let i = 0, n = charset.length; i < length; i++) {
      retVal += charset.charAt(Math.floor(Math.random() * n));
    }
    return retVal;
  };

  const handleSubmit = e => {
    e.preventDefault();
    if (passwordLength === '') return;
    if (isEditing) {
      setPasswordItems(prevState => {
        const newItems = [...prevState];
        const index = newItems.findIndex(item => item.id === editId);
        newItems.splice(index, 1, {
          id: editId,
          title: passwordTitle,
          password: editingPassword,
          isVisible: false,
        });
        return newItems;
      });
      setIsEditing(false);
      setPasswordTitle('');
      setEditId('');
      setEditingPassword('');
      return;
    }
    setPasswordItems(prevState => [
      ...prevState,
      {
        id: uuidv4(),
        title: passwordTitle,
        password: generatePassword(),
        isVisible: false,
      },
    ]);
    setPasswordTitle('');
  };

  const handleVisible = (id, title, password, isVisible) => {
    if (isVisible) {
      setPasswordItems(prevState => {
        const newItems = [...prevState];
        const index = newItems.findIndex(item => item.id === id);
        newItems.splice(index, 1, {
          id,
          title,
          password,
          isVisible: false,
        });
        return newItems;
      });
    } else {
      setPasswordItems(prevState => {
        const newItems = [...prevState];
        const index = newItems.findIndex(item => item.id === id);
        newItems.splice(index, 1, {
          id,
          title,
          password,
          isVisible: true,
        });
        return newItems;
      });
    }
  };

  const handleDelete = id =>
    setPasswordItems(prevState => prevState.filter(item => item.id !== id));

  const handleEdit = (id, title, password) => {
    inputTitleRef.current.focus();
    setIsEditing(prevState => !prevState);
    setPasswordTitle(title);
    setEditId(id);
    setEditingPassword(password);
  };

  const handleCancel = () => {
    setIsEditing(false);
    setPasswordTitle('');
    setEditId('');
    setEditingPassword('');
  };

  useEffect(() => inputPasswordRef.current.focus(), []);

  useEffect(
    () => localStorage.setItem('Passwords', JSON.stringify(passwordItems)),
    [passwordItems]
  );

  return (
    <div className="manager">
      <div className="lg-container">
        <div className="manager-parent">
          <i className="key fas fa-key"></i>
          <h1 className="manager-title">
            {isEditing ? 'Edit mode' : 'Password Manager'}
          </h1>
          <form className="manager-form" onSubmit={handleSubmit}>
            {isEditing && (
              <label className="manager-form-label" htmlFor="password-title">
                On edit mode, <br /> you may only change the title.
              </label>
            )}
            <div className="manager-form-input-container">
              {!isEditing && (
                <input
                  type="number"
                  className="manager-input"
                  onChange={handlePasswordLengthChange}
                  ref={inputPasswordRef}
                  value={passwordLength}
                  name="password-length"
                  id="password-input"
                  placeholder="Password length..."
                  autoComplete="off"
                  max="30"
                  min="5"
                  required={isEditing ? false : true}
                  disabled={isEditing ? true : false}
                />
              )}
              <input
                type="text"
                className="manager-input"
                onChange={handlePasswordTitleChange}
                ref={inputTitleRef}
                value={passwordTitle}
                name="password-title"
                id="password-title"
                placeholder="Enter title..."
                autoComplete="off"
                maxLength="20"
                required={true}
              />
            </div>
            <div className="manager-form-btn-container">
              <button type="submit" className="btn-border">
                {isEditing ? 'update' : 'generate'}
              </button>
              {isEditing && (
                <button
                  type="button"
                  onClick={handleCancel}
                  className="btn-border"
                >
                  cancel
                </button>
              )}
            </div>
          </form>
          <ul className="manager-ul">
            {passwordItems.length === 0 ? (
              <div className="lock-container">
                <i className="lock fas fa-lock"></i>
              </div>
            ) : (
              passwordItems.map(item => (
                <li className="manager-ul-li" key={item.id}>
                  <h5 className="manager-ul-li-title">{item.title}</h5>
                  <div className="manager-ul-li-container">
                    <input
                      className="hidden-password"
                      contentEditable="false"
                      type={!item.isVisible ? 'password' : 'text'}
                      value={item.password}
                      readOnly
                    />
                    <div>
                      <button
                        onClick={() =>
                          handleVisible(
                            item.id,
                            item.title,
                            item.password,
                            item.isVisible
                          )
                        }
                        title="Reveal"
                        className="manager-li-icons"
                        disabled={isEditing ? true : false}
                      >
                        <i className="fas fa-eye"></i>
                      </button>
                      <button
                        onClick={() => handleDelete(item.id)}
                        title="Delete"
                        className="manager-li-icons"
                        disabled={isEditing ? true : false}
                      >
                        <i className="fas fa-minus-circle"></i>
                      </button>
                      <button
                        onClick={() =>
                          handleEdit(item.id, item.title, item.password)
                        }
                        title="Edit"
                        className="manager-li-icons"
                        disabled={isEditing ? true : false}
                      >
                        <i className="fas fa-edit"></i>
                      </button>
                    </div>
                  </div>
                </li>
              ))
            )}
          </ul>
        </div>
      </div>
    </div>
  );
};

// App
const App = () => <PasswordManager />;

// Render
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

 

 

 

And now if you open index.html file inside the browser you will see the below screenshot

 

 

Leave a Reply