JavaScript Password Generator

02/12/2021

Contents

Demo

Full Screen

Code

HTML

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>JavaScript Password Generator</title>
    <link rel="stylesheet" type="text/css" href="https://demo.plantpot.works/assets/css/normalize.css">
    <link rel="stylesheet" href="https://use.typekit.net/opg3wle.css">
    <link rel="stylesheet" type="text/css" href="style.css">
  </head>
  <body>
    <div id="container">
      <div class="box">
        <div class="result-container">
          <input id="result" class="result" type="text" placeholder="Enter a password">
          <div class="btns">
            <div id="clipboard" class="btn"></div>
            <div id="generate" class="btn"></div>
          </div>
        </div>
        <div class="options">
          <div class="option">
            <label for="length">Password length</label>
            <div class="row">
              <input id="slider" class="slider" type="range" min="0" max="99" value="12">
              <input id="length" class="length" type="number" min='0' max='99' value='12'>
            </div>
          </div>
          <div class="option">
            <input type="checkbox" id="uppercase" checked>
            <label for="uppercase" class="checkbox">Uppercase</label>
          </div>
          <div class="option">
            <input type="checkbox" id="lowercase" checked>
            <label for="lowercase" class="checkbox">Lowercase</label>
          </div>
          <div class="option">
            <input type="checkbox" id="numbers" checked>
            <label for="numbers" class="checkbox">Numbers</label>
          </div>
          <div class="option">
            <input type="checkbox" id="symbols" checked>
            <label for="symbols" class="checkbox">Symbols</label>
          </div>
        </div>
      </div>
    </div>
    <script src="password.js"></script>
  </body>
</html>

CSS

@charset "utf-8";
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
html {
  font-size: 16px;
}
body {
  background-color: #3d3935;
  font-family: futura-pt, sans-serif;
  -webkit-tap-highlight-color: rgba(0,0,0,0);
}
#container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100vh;
  padding: 10px;
}
.box {
  width: 100%;
  max-width: 280px;
  padding: 20px;
  background-color: #fff7d5;
  color: #3d3935;
}
.options {
  margin-top: 20px;
}
.option {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-start;
  margin-top: 10px;
}
.row {
  width: 100%;
  margin-bottom: 10px;
}
label {
  font-size: 1rem;
  letter-spacing: 1px;
}
input[type="number"]::-webkit-inner-spin-button {
  display: none;
}
input[type=checkbox] {
  display: none;
}
.slider {
  -webkit-appearance: none;
  appearance: none;
  height: 4px;
  border: none;
  border-radius: 3px;
  background-color: #ab830c;
  outline: none;
  cursor: pointer;
}
.slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 15px;
  height: 15px;
  border: none;
  border-radius: 50%;
  background: #ed2b04;
}
.length {
  width: 30px;
  padding: 0;
  border: none;
  border-bottom: solid 1px #030301;
  border-radius: 0;
  background-color: transparent;
  color: #3d3935;
  font-size: 1.125rem;
  text-align: center;
  outline: none;
}
.checkbox {
  position: relative;
  padding-left: 25px;
  line-height: 1.2;
  cursor: pointer;
}
.checkbox::before {
  position: absolute;
  top: 0;
  left: 0;
  width: 16px;
  height: 16px;
  border: 1px solid #a63923;
  border-radius: 2px;
  content: '';
}
.checkbox::after {
  opacity: 0;
  position: absolute;
  top: 2px;
  left: 7px;
  transform: rotate(45deg);
  width: 3px;
  height: 10px;
  border-right: 2px solid #fff;
  border-bottom: 2px solid #fff;
  content: '';
}
input[type=checkbox]:checked + .checkbox::before {
  background-color: #a63923;
}
input[type=checkbox]:checked + .checkbox::after {
  opacity: 1;
}
.result-container {
  position: relative;
  width: 100%;
  padding-bottom: 4px;
  border-bottom: solid 1px #030301;
}
.result {
  border: none;
  font-size: 1.125rem;
  background: none;
  outline: none;
}
.btns {
  display: flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  top: 0;
  right: 0;
}
.btn {
  cursor: pointer;
  width: 20px;
  height: 20px;
}
#clipboard.btn {
  background-image: url(ic_copy.svg);
  background-position: center;
  background-size: 14px;
  background-repeat: no-repeat;
}
#generate.btn {
  background-image: url(ic_generate.svg);
  background-position: center;
  background-size: 18px;
  background-repeat: no-repeat;
}

JavaScript

const resultEl = document.getElementById('result');
const lengthEl = document.getElementById('length');
const slider = document.getElementById('slider');
const uppercaseEl = document.getElementById('uppercase');
const lowercaseEl = document.getElementById('lowercase');
const numbersEl = document.getElementById('numbers');
const symbolsEl = document.getElementById('symbols');
const generateEl = document.getElementById('generate');
const clipboard = document.getElementById('clipboard');

const randomFunc = {
  lower: getRandomLower,
  upper: getRandomUpper,
  number: getRandomNumber,
  symbol: getRandomSymbol
}

slider.addEventListener('input', () => {
  lengthEl.value = slider.value;
});

lengthEl.addEventListener('input', () => {
  slider.value = lengthEl.value;
});

clipboard.addEventListener('click', () => {
  const textarea = document.createElement('textarea');
  const password = resultEl.value;

  if(!password) { return; }

    textarea.value = password;
    document.body.appendChild(textarea);
    textarea.select();
    document.execCommand('copy');
    textarea.remove();
    alert('Password copied to clipboard');
});

generate.addEventListener('click', () => {
  const length = +lengthEl.value;
  const hasLower = lowercaseEl.checked;
  const hasUpper = uppercaseEl.checked;
  const hasNumber = numbersEl.checked;
  const hasSymbol = symbolsEl.checked;

  resultEl.value = generatePassword(hasLower, hasUpper, hasNumber, hasSymbol, length);
});

function generatePassword(lower, upper, number, symbol, length) {
  let generatedPassword = '';
  const typesCount = lower + upper + number + symbol;
  const typesArr = [{lower}, {upper}, {number}, {symbol}].filter(item => Object.values(item)[0]);

  if(typesCount === 0) {
    return '';
  }

  for(let i=0; i {
      const funcName = Object.keys(type)[0];
      generatedPassword += randomFunc[funcName]();
    });
  }

  const finalPassword = generatedPassword.slice(0, length);

  return finalPassword;
}

function getRandomLower() {
  return String.fromCharCode(Math.floor(Math.random() * 26) + 97);
}

function getRandomUpper() {
  return String.fromCharCode(Math.floor(Math.random() * 26) + 65);
}

function getRandomNumber() {
  return +String.fromCharCode(Math.floor(Math.random() * 10) + 48);
}

function getRandomSymbol() {
  const symbols = '!@#$%^&*(){}[]=<>/,.'
  return symbols[Math.floor(Math.random() * symbols.length)];
}