Video Tutorial:
If you are interested to learn by watching a video tutorial rather than reading this block post, you can check out the video below. Also, subscribe to my YouTube channel where I post new tutorials tricks and tips every alternate day.
Project Folder Structure:
Let’s first create the project folder structure. We create a project folder called wordle. Inside this folder, we have three files these files index.html, style.css, and script.js. The first file is the HTML document. While the second one is the stylesheet. We finally have the script file.
HTML:
The HTML file consists of elements that build the layout of our app. Copy the code below and paste it into your HTML document.
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Wordle</title>
<!-- Google Font -->
<link
href="https://fonts.googleapis.com/css2?family=Poppins:wght@600&display=swap"
rel="stylesheet"
/>
<!-- Stylesheet -->
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="wrapper">
<div class="container"></div>
<div class="rules">
<img src="rules.svg" />
</div>
<div class="win-screen hide"></div>
</div>
<button class="submit hide">Submit</button>
<!-- Script -->
<script src="script.js"></script>
</body>
</html>
CSS:
Next, we style the game using CSS. For this copy, the code provided to you below and paste it into your style sheet.
* {
padding: 0;
margin: 0;
box-sizing: border-box;
font-family: "Poppins", sans-serif;
}
body {
height: 100vh;
background: linear-gradient(135deg, #c59cff, #7e5bfb);
}
.wrapper {
position: absolute;
transform: translate(-50%, -50%);
top: 50%;
left: 50%;
display: flex;
gap: 1em;
background-color: #ffffff;
padding: 1em;
border-radius: 0.5em;
box-shadow: 0 2.5em 3.75em rgba(30, 19, 70, 0.3);
}
.container,
.rules {
width: 18.75em;
height: 22.5em;
position: relative;
}
.input-group {
display: grid;
width: 100%;
grid-template-columns: auto auto auto auto auto;
column-gap: 0.2em;
margin: 0.2em 0;
}
.input-box {
font-size: 2em;
width: 1.7em;
height: 1.7em;
text-align: center;
display: block;
border: 1px solid #000000;
line-height: 1;
font-weight: 600;
text-transform: uppercase;
}
.input-box:disabled {
color: #000000;
}
.correct {
background-color: #6aaa64;
}
.exists {
background-color: #c9b458;
}
.incorrect {
background-color: #787c7e;
}
.correct,
.exists,
.incorrect {
color: #ffffff;
}
.win-screen {
font-weight: 400;
position: absolute;
background-color: #ffffff;
height: 100%;
width: 100%;
top: 0;
left: 0;
border-radius: 0.5em;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
gap: 1em;
}
.win-screen button {
font-size: 1.2em;
background-color: #7e5bfb;
border: none;
outline: none;
font-weight: 400;
padding: 0.8em 2em;
border-radius: 2em;
}
.hide {
display: none;
}
@media screen and (max-width: 700px) {
.wrapper {
flex-direction: column;
transform: translateX(-50%);
left: 50%;
top: 0.5em;
}
}
Javascript:
We finally had functionality to the game with JavaScript we do this in the following steps:
Create initial references
Create an initial setup
A function to generate a random word
A function to update input to disabled status and set focus
The logic for writing in inputs
Comparison logic
let words = [
"Zebra",
"Sling",
"Crate",
"Brick",
"press",
"truth",
"sweet",
"salty",
"alert",
"check",
"roast",
"toast",
"shred",
"cheek",
"shock",
"czech",
"woman",
"wreck",
"court",
"coast",
"flake",
"think",
"smoke",
"unrig",
"slant",
"ultra",
"vague",
"pouch",
"radix",
"yeast",
"zoned",
"cause",
"quick",
"bloat",
"level",
"civil",
"civic",
"madam",
"house",
"delay",
];
let container = document.querySelector(".container");
let winScreen = document.querySelector(".win-screen");
let submitButton = document.querySelector(".submit");
let inputCount, tryCount, inputRow;
let backSpaceCount = 0;
let randomWord, finalWord;
//Detect touch device
const isTouchDevice = () => {
try {
//We try to create TouchEvent (it would fail for desktops and throw error)
document.createEvent("TouchEvent");
return true;
} catch (e) {
return false;
}
};
//Initial Setup
const startGame = async () => {
winScreen.classList.add("hide");
container.innerHTML = "";
inputCount = 0;
successCount = 0;
tryCount = 0;
finalWord = "";
//Creating the grid
for (let i = 0; i < 6; i++) {
let inputGroup = document.createElement("div");
inputGroup.classList.add("input-group");
for (let j = 0; j < 5; j++) {
//Disabled by default. We will enable one by one
inputGroup.innerHTML += `<input type="text" class="input-box" onkeyup="checker(event)" maxlength="1" disabled>`;
}
await container.appendChild(inputGroup);
}
inputRow = document.querySelectorAll(".input-group");
inputBox = document.querySelectorAll(".input-box");
updateDivConfig(inputRow[tryCount].firstChild, false);
randomWord = getRandom();
console.log(randomWord);
};
//Get random word
const getRandom = () =>
words[Math.floor(Math.random() * words.length)].toUpperCase();
//Update input to disabled status and set focus
const updateDivConfig = (element, disabledStatus) => {
element.disabled = disabledStatus;
if (!disabledStatus) {
element.focus();
}
};
//Logic for writing in the inputs
const checker = async (e) => {
let value = e.target.value.toUpperCase();
//disable current input box
updateDivConfig(e.target, true);
if (value.length == 1) {
//if the word is lesss than 5 length and the button isn't backspace
if (inputCount <= 4 && e.key != "Backspace") {
//Attach the letter to the final word
finalWord += value;
if (inputCount < 4) {
//enable next
updateDivConfig(e.target.nextSibling, false);
}
}
inputCount += 1;
} else if (value.length == 0 && e.key == "Backspace") {
//Empty input box anduser press Backspace
finalWord = finalWord.substring(0, finalWord.length - 1);
if (inputCount == 0) {
//For first inputbox
updateDivConfig(e.target, false);
return false;
}
updateDivConfig(e.target, true);
e.target.previousSibling.value = "";
//enable previous and decrement count
updateDivConfig(e.target.previousSibling, false);
inputCount = -1;
}
};
//When user presses enter/backspace and all the inputs are filled
window.addEventListener("keyup", (e) => {
if (inputCount > 4) {
if (isTouchDevice()) {
submitButton.classList.remove("hide");
}
if (e.key == "Enter") {
validateWord();
} else if (e.key == "Backspace") {
inputRow[tryCount].lastChild.value = "";
finalWord = finalWord.substring(0, finalWord.length - 1);
updateDivConfig(inputRow[tryCount].lastChild, false);
inputCount -= 1;
}
}
});
//Comparison Logic
const validateWord = async () => {
if (isTouchDevice()) {
submitButton.classList.add("hide");
}
let failed = false;
//Get all input boxes of current row
let currentInputs = inputRow[tryCount].querySelectorAll(".input-box");
//Check if it is a valid english word
await fetch(
`https://api.dictionaryapi.dev/api/v2/entries/en/${finalWord}`
).then((response) => {
if (response.status == "404") {
console.clear();
alert("Please Enter Valid Word");
failed = true;
}
});
//If not then stop here
if (failed) {
return false;
}
//Initially set these
let successCount = 0;
let successLetters = "";
//Checks for both words
for (let i in randomWord) {
//if same then green
if (finalWord[i] == randomWord[i]) {
currentInputs[i].classList.add("correct");
successCount += 1;
successLetters += randomWord[i];
} else if (
randomWord.includes(finalWord[i]) &&
!successLetters.includes(finalWord[i])
) {
//If the letter exist in the chosen word and is not present in the success array then yellow
currentInputs[i].classList.add("exists");
} else {
currentInputs[i].classList.add("incorrect");
}
}
//Increment try count
tryCount += 1;
//If all letters are correct
if (successCount == 5) {
//Display the win banner after 1 second
setTimeout(() => {
winScreen.classList.remove("hide");
winScreen.innerHTML = `
<span>Total guesses: ${tryCount}</span>
<button onclick="startGame()">New Game</button>
`;
}, 1000);
} else {
//unsuccessful so next attempt
inputCount = 0;
finalWord = "";
if (tryCount == 6) {
//all attempts wrong
tryCount = 0;
winScreen.classList.remove("hide");
winScreen.innerHTML = ` <span>You lose</span>
<button onclick="startGame()">New Game</button>`;
return false;
}
//for next attempt move to first child of next row
updateDivConfig(inputRow[tryCount].firstChild, false);
}
inputCount = 0;
};
window.onload = startGame();
That’s all for this tutorial. If you face any issues while creating this project you can download the source code by clicking on the download button below also so if you have any queries suggestions or feedback you can comment below.
Happy coding!


Hello, I absolutely love your works!
Might be wrong but it seems that correct but misplaced chars aren’t counted. Leading in a wrong result if the randomWord is “Cheeks” and the finalWord is “Eerie”. All 3 “e” will be yellow.
I played around with that Wordle game mechanism but on Swift 🙂
Hi,
Thanks for a great tutorial – I learned lots!
But I think the js script has an error on line 127:
inputCount = -1;
It should be:
inputCount -= 1;