UI password generator component

Ever since ui frameworks get popular, i got caught up in using different frameworks. Even though, it is great to be engaged with different frameworks, i always wanted to make a series of ui component in vanilla js. In this series, i want to publish small ui components which are written in only pure js, css and html. In this series, i will use the ui component in https://www.frontendmentor.io/ which provides different kind of challanges. We will tackle them one by one. Let’s start with password generator component. Here is the component design:

Since i am planning to keep things simple, i will start off by creating html file.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>Password Generator App</title>
<link rel="stylesheet" href="index.css">
<script type="module" src="index.js"></script>
</head>
<body>
<div class="container">
<div class="title">Password Generator</div>
</div>
</body>
</html>

As you can see, i pointed to an external css file through the href attribute. Let’s create this file.

body {
background: black;
color: #cbcbcb;
font-weight: bold;
font-size: 15px;
}
.container {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
padding: 10px;
width: 400px;
}

I started by styling body and div named container. I centered “container” vertically and horizontally inside the body. Beside that external css file, i also used external script file. I am creating the script file now but i am not writing any script in it until i am done with designing and styling my app. Let’s complete our design first. As you can see in above picture, our component was composed of 2 different blocks “password” and “options”. Let’s start with “password block” design.

<div class="password-block">
<div id="password">#P4^^ASWNU</div>
<img src="../assets/copy.svg" alt="copy image" id="copy-image">
</div>

i want to style “password-block” before getting into designing “options block”.

.block {
background: #343434;
border-radius: 2px;
padding: 10px;
margin-top: 10px;
}
.password-block {
display: flex;
align-items: center;
margin-top: 20px;
justify-content: space-between;
}
#password {
color: #6c6c6c;
font-size: 25px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

I create “block” class for common styles between “password” and “options”. I still need to create two different class to make them look different from one another. In “password-block” class, i am centering the content vertically while distributing items evenly the first item is flush with the start, the last is flush with the end. In “password” class i am displaying an ellipsis when the text is overflowed. We are done with “password block” design and styling. It is time to move into “options-block”.

In options-block consists of more elements than password-block. Let’s split it into different groups. We will have three different nested blocks in here. “Character length”, “Character type“, “Strength” and last but not least is “Generate button”. Let”s start with “Character Length” block design and style.

<div>
<div class="password-length-header-block">
<label>Character Length</label>
<label id="password-length">10</label>
</div>
<div>
<input type="range" min="0" max="20" value="10"/>
</div>
</div>
.password-length-header-block {
display: flex;
justify-content: space-between;
font-size: 20px;
letter-spacing: 2px;
color: #b2b2b2;
}
#password-length {
font-size: 30px;
color: #80eda7;
}
input[type="range"] {
-webkit-appearance: none;
margin-right: 10px;
width: 100%;
height: 4px;
background: black;
border-radius: 5px;
background-image: linear-gradient(#80eda7, #80eda7);
background-size: 48% 100%;
background-repeat: no-repeat;
}

input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
height: 20px;
width: 20px;
border-radius: 50%;
background: white;
cursor: ew-resize;
box-shadow: 0 0 2px 0 #555;
transition: background .3s ease-in-out;
}

As you can see, i am not using any fancy third party library to create range element. I am basically using what html provides us. The only thing i did is to change the way how it looks accessing “input[type=range]” and its attributes through css file. Let me define what i am doing over there one line by one. “password-length-header-block” class covers the header of character length part and i used similar styles to what i used in “password block” in order to put header to the left and put the character length to the right. Secondly, i create input range for slider control. Even though, its functionality works well for me, it still needs to be improved by design. This is why i get access to its attributes through css file. In order to change the way how thumb which is used to alter the input’s numerical value looks in slider, i used input[type=”range”]::-webkit-slider-thumb. You can change based on your design.

We can move into second group named options. Let’s start off creating design as always.

<div class="option-block">
<input id="uppercase" type="checkbox" name="uppercase" />
<label style="word-wrap:break-word">Include Uppercase letters</label>
</div>
<div class="option-block">
<input id="lowercase" type="checkbox" name="lowercase" />
<label style="word-wrap:break-word">Include Lowercase letters</label>
</div>
<div class="option-block">
<input id="numbers" type="checkbox" name="numbers" />
<label style="word-wrap:break-word">Include Numbers</label>
</div>
<div class="option-block">
<input id="symbols" type="checkbox" name="symbols" />
<label style="word-wrap:break-word">Include Symbols</label>
</div>

There is nothing fancy here but using multiple of same type of checkboxes. It is also same story here. Checkbox fulfills our app’s functionality. But we need to make it look like our design. To make it happen, let’s get back to css file.

input[type="checkbox"]:checked {
accent-color: #80eda7;
}

Changing accent-color when checkbox is checked will make the design look like we want.

The only thing is left is to create a “generate button”. In here i did the same thing more or less by centering button vertically and horizontally.

<div id="button-container">
GENERATE ->
</div>
#button-container {
background: #80eda7;
height: 50px;
border-radius: 2px;
margin-top: 10px;
color: black;
font-weight: 700;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}

Since we are done html and css implementation, we can get into implementing its functionality. In order to keep things simple and readible, i’d like to put document elements at the top of the file while putting event listeners at the bottom of the file. You can read all the elements that you thought that would come in handy.

const D = document;

const $isUppercase = D.getElementById("uppercase");
const $isLowercase = D.getElementById("lowercase");
const $isNumbers = D.getElementById("numbers");
const $isSymbols = D.getElementById("symbols");
const $password = D.getElementById("password");
let $passwordLength = D.getElementById("password-length");
const $generateBtn = D.getElementById("button-container");
const $copyBtn = D.getElementById("copy-image");
const $rangeInputs = D.querySelectorAll('input[type="range"]')
$generateBtn.onclick = () => generatePassword();
$copyBtn.onclick = () => copyPassword();

In this app, what we are doing is to create random text named “password” based on user options. Once the user clicks the “generate” button, we will read all the options that were entered by user and generate one. I think, it would be great if we start off by creating “generate button” functionality. We will add other logic when we need.

function generatePassword() {
let chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

if ($isUppercase.checked) {
chars += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
}
if ($isLowercase.checked) {
chars += "abcdefghijklmnopqrstuvwxyz";
}
if ($isNumbers.checked) {
chars += "0123456789";
}
if ($isSymbols.checked) {
chars += "!@#$%^&*()";
}
let passwordNewGenerated = "";
for (let i = 0; i <= $passwordLength.innerText; i++) {
const randomNumber = Math.floor(Math.random() * chars.length);
passwordNewGenerated += chars.substring(randomNumber, randomNumber +1);
}
$password.innerText = passwordNewGenerated;
};

As you can see, in this code block we are reading every value from dom and based on what user selects we are creating random password. The other logic we need to add is to read value from input range. We have to do some work to be able to read the value. We are updating passwordLength through input’s onChange event listener.

function handleInputChange(e) {
let target = e.target;
const min = target.min;
const max = target.max;
const val = target.value;
target.style.backgroundSize = (val - min) * 100 / (max - min) + '% 100%';
$passwordLength.innerText = val;
}

$rangeInputs.forEach(input => {
input.addEventListener('input', handleInputChange)
})

The only thing left is to implement copy password logic. It will be triggered by clicking a copy button near the password.

function copyPassword() {
navigator.clipboard.writeText($password.innerText);
}

In this way, we came to end of this ui component. I will share a demo with you here if you like to see all the code files at one place. https://codepen.io/giana/pen/yYBpVY

I started off by creating a password generator component using html, css and js without making use of any frameworks. In this series, i will continue tackling different ui components and try to solve them with vanilla js. I believe that knowing the basics deeply will help you understand any frameworks out there. Please leave comments if you have any question.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store