Tic Tac Toe is one of the most popular beginner-friendly games that every developer tries while learning JavaScript. It is simple, interactive, and helps you understand core programming concepts like DOM manipulation, event handling, and game logic.
In this tutorial, we will build a complete Tic Tac Toe game using HTML, CSS, and JavaScript. This project is perfect for beginners who want to improve their front-end development skills.
What You Will Learn
- How to create a game layout using HTML
- How to style a grid using CSS
- How to handle user clicks using JavaScript
- How to detect a winner
- How to reset the game
Game Overview
The game consists of a 3×3 grid where two players take turns marking spaces. One player uses “O” and the other uses “X”. The goal is to get three symbols in a row, column, or diagonal.
Step 1: HTML Structure
The HTML creates the basic structure of the game including the grid container, result section, and play again button.
<div class="code-container">
<h1 class="text-center">Tic Tac Toe</h1>
<div class="tic-tac-toe-box"></div>
<p class="text-center">Player 1 = 0<br>Player 2 = X</p>
<h2 class="text-center winner-result">Player <span id="player-win"></span> Win</h2>
<button type="button" class="play-game-again">Play Again</button>
</div>
The grid boxes will be dynamically created using JavaScript.
Step 2: Styling with CSS
CSS is used to design the layout and make the game visually appealing.
@import url("https://fonts.googleapis.com/css2?family=Roboto&display=swap");
body{
font-family: 'Roboto', sans-serif;
font-size: 14px;
}
.code-container {
max-width: 100%;
width: 450px;
padding: 30px 10px;
box-shadow: 0px 0px 10px #0000003d;
border-radius: 10px;
}
.tic-tac-toe-box {
display: grid;
grid-template-columns: repeat(3,minmax(0,1fr));
width: 260px;
height: 260px;
margin: 0 auto 20px auto;
}
.tic-tac-toe-box input {
outline: none;
text-align: center;
font-size: 55px;
cursor: pointer;
border-radius: 0;
border: 1px solid #000;
}
.text-center{
text-align:center;
}
.winner-result{
display:none;
color: #14936f;
}
.code-container h1 {
margin: 0 0 20px 0;
}
.play-game-again {
background: #ff7600;
border: none;
color: #fff;
padding: 5px 20px;
border-radius: 5px;
margin: 0 auto;
display: none;
cursor: pointer;
}
Step 3: Creating Game Boxes with JavaScript
Instead of manually writing 9 boxes in HTML, we generate them using JavaScript.
let ticBox = ''
for(let j = 1; j < 10; j++){
ticBox += '<input type="text" class="tic-box" readonly data-value="'+j+'">'
}
document.querySelector(".tic-tac-toe-box").innerHTML = ticBox
This loop creates 9 input boxes dynamically.
Step 4: Game Logic
We define all possible winning combinations:
let winingChances = [
[1,2,3],
[4,5,6],
[7,8,9],
[1,4,7],
[2,5,8],
[3,6,9],
[1,5,9],
[3,5,7],
]
These combinations represent rows, columns, and diagonals.
Step 5: Handling Player Turns
We alternate between Player 1 (O) and Player 2 (X) using a toggle variable.
Each click updates the box value and stores the move.
Step 6: Checking Winner
After every move, we check if a player has achieved any winning combination.
let isFounded_1 = winingChances[i].every(elem => storeWinOne.includes(elem))
If a match is found, we declare the winner and disable all boxes.
Step 7: Reset Game
The “Play Again” button resets everything:
const resetGame = () => {
click = 0
storeWinOne = []
storeWinTwo = []
}
This allows players to start a new game.
Complete JavaScript Code
Below is the full working logic of the game:
//Add Boxes
let ticBox = ''
for(let j = 1; j < 10; j++){
ticBox += '<input type="text" class="tic-box" readonly="" data-value="'+j+'">'
}
document.querySelector(".tic-tac-toe-box").insertAdjacentHTML('afterbegin', ticBox)
//Set first click
let firstClick = 0
//Winning Matches
let winingChances = [
[1,2,3],
[4,5,6],
[7,8,9],
[1,4,7],
[2,5,8],
[3,6,9],
[1,5,9],
[3,5,7],
]
//Player 1 Clicked Box
let storeWinOne = new Array()
//Player 2 Clicked Box
let storeWinTwo = new Array()
let clickBox = document.querySelectorAll(".tic-box")
let click = 0
//Disable all box after win
const disableAll = (player) => {
for(let i = 0;i < clickBox.length; i++){
clickBox[i].disabled = true
}
document.querySelector("#player-win").innerHTML = player
document.querySelector(".winner-result").style.display = "block"
document.querySelector(".play-game-again").style.display = "block"
firstClick = 0
}
//Reset Game
const resetGame = () => {
for(let i = 0;i < clickBox.length; i++){
clickBox[i].disabled = false
clickBox[i].classList.remove("clicked")
clickBox[i].value = ''
}
click = 0
storeWinOne = []
storeWinTwo = []
document.querySelector(".play-game-again").removeAttribute("style")
document.querySelector(".winner-result").removeAttribute("style")
firstClick = 0
}
//Play Again
let playAgainBtn = document.querySelector(".play-game-again")
playAgainBtn.addEventListener('click', function(e) {
resetGame()
});
Array.prototype.forEach.call(clickBox, function(element) {
element.addEventListener('click', function(e) {
if(e.target.classList.contains("clicked")) return false
click++
firstClick == 0 ? firstClick = 1 : firstClick = 0
e.target.setAttribute("data", firstClick)
e.target.classList.add("clicked")
if(firstClick == 0){
e.target.value = 'X'
}else{
e.target.value = '0'
}
if(firstClick == 1 && e.target.classList.contains("clicked")){
storeWinOne.push(Number(e.target.getAttribute("data-value")))
}
if(firstClick == 0 && e.target.classList.contains("clicked")){
storeWinTwo.push(Number(e.target.getAttribute("data-value")))
}
for(let i = 0; i < winingChances.length; i++){
let isFounded_1 = winingChances[i].every(elem => storeWinOne.includes(elem))
let isFounded_2 = winingChances[i].every(elem => storeWinTwo.includes(elem))
if(isFounded_1){
disableAll(1)
return false
}
if(isFounded_2){
disableAll(2)
return false
}
}
if(click == 9){
resetGame()
}
});
});
Preview Link
https://code.bydev24.com/snippets/tic-tac-toe
Features of This Project
- Dynamic grid generation
- Turn-based gameplay
- Winner detection
- Reset functionality
- Simple and clean UI
Why This Project Is Important
This project helps beginners understand real-world JavaScript concepts like DOM manipulation, arrays, loops, and event handling.
It is also a great addition to your portfolio.
Conclusion
Building a Tic Tac Toe game is a great way to practice your front-end development skills. With just HTML, CSS, and JavaScript, you can create a fully functional interactive game.
Try modifying this project by adding animations, AI opponent, or score tracking to make it more advanced.

💡 I built this simple Tic Tac Toe game to help beginners understand how JavaScript actually works in real projects.
If you’re just starting out, try modifying this project:
👉 Add score tracking
👉 Add animations
👉 Or even build an AI opponent