I am sure you have played tictactoe as a child. In this article, we will build tictactoe using plain JavaScript step by step. Let's go! I recommend you to exercise what you see so that you will get the most out of this article. The source code can be found at my . Open your favorite IDE, mine is , and open a new project folder. We will create the files one by one. This will be our directory structure: Github repository VSCode |- index.html |- /js |- main.js |- /stylesheet |- main.css Let's start with the . In the body of the html, we will add the title, form for filling player names, a submit button to play, container for clickable boxes, and restart button. Remember to also put links to your stylesheet at the top and your script at the bottom. The container to play the game will be invisible at first. After the players fill the form and click submit, we will make the container visible. index.html TICTACTOE Tic Tac Toe Enter players' names and click play to start the game! Player 1 (X) Player 2 (O) Play Board: Restart <!DOCTYPE html> < = > html lang "en" < > head < = > meta charset "UTF-8" < = = > meta name "viewport" content "width=device-width, initial-scale=1.0" < = = > meta http-equiv "X-UA-Compatible" content "ie=edge" < = = > link rel "stylesheet" href "styles/styles.css" < > title </ > title </ > head < > body < = > h2 class "text-center mt-4" < = > span class "mid-title" </ > span </ > h2 < = > h5 class "text-center" </ > h5 < = > div class "container" < = > form class "player-info mb-4" < = > div class "form-group" < = > label for "player1" </ > label < = = = = > input type "text" class "form-control" id "player1" placeholder "Name of player 1" </ > div < = > div class "form-group" < = > label for "player2" </ > label < = = = = > input type "text" class "form-control" id "player2" placeholder "Name of player 2" </ > div < = = > button type "submit" class "btn btn-primary" </ > button </ > form < = > div class "col-4 offset-4 place hidden" < = > div class "alert alert-primary game-status text-center" < > h4 </ > h4 </ > div < = > div class "container mx-auto" < = > div id "board" < = > div class "cell text-center display-4" </ > div < = > div class "cell text-center display-4" </ > div < = > div class "cell text-center display-4" </ > div < = > div class "cell text-center display-4" </ > div < = > div class "cell text-center display-4" </ > div < = > div class "cell text-center display-4" </ > div < = > div class "cell text-center display-4" </ > div < = > div class "cell text-center display-4" </ > div < = > div class "cell text-center display-4" </ > div </ > div </ > div < = = > button id "reset" class "mt-4 text-center btn btn-primary" </ > button </ > div </ > div < = > script src "js/main.js" </ > script </ > body </ > html In the file, we will add our styles. I've used bootswatch. It is a customized version of bootstrap. You can your own style if you want. Go ahead to their website, choose a theme and download the minified css and put that at the top the css file. I have added my own style after shown below. You have to add the bootswatch minified css at the top of this file. main.css { : solid black; : flex; : wrap; : ; : ; } { : solid black; : ; : ; } { : none; } , { : ; } { : red; } #board border 2px display flex-wrap height 270px width 245px .cell border 2px height 80px width 80px .hidden display .player-info .game-status width 80% .mid-title color Ok, now let's go to the main part, file. All methods below this paragraph are JavaScript methods that will be in the file.Let's start with the playerFactory. The playerFactory will be the factory for players. Factories are like classes. You can also use class instead of factory but factories are preferred. You can read more about classes and factories . The playerFactory will accept the player name and the mark ('X' or 'O'). It will have a method to play when it's the player's turn. The playTurn method will accept a board which will be the game board and the cell. It will find the index of the cell and return it if it's empty or it will return null if it's occupied. main.js main.js here playerFactory = { playTurn = { idx = board.cells.findIndex( position === cell); (board.boardArray[idx] === ) { board.render(); idx; } ; }; { name, mark, playTurn }; }; const ( ) => name, mark const ( ) => board, cell const => position if '' return return null return Next, we will make the board module. A module is similar to a factory in JavaScript but they are like static classes. They can be called without being instantiated. We will have the board array to hold the 9 positions in the game. We will use DOM manipulation to select and the values of html elements. The render method will make the value of the html cells equal to the board array. The reset method will reset the board making all values to an empty string. The checkWin method will check the winning positions in a tictactoe game. For example, if you put continuous 'X' in a row, you will win. If we take the first row, that position will be the first, second and third. But since arrays start from zero, we will have to deduct one from each and it will be zero, one, two or [0, 1, 2] which you see as the first entry in the winArrays variable. The winArray variable is filled with all those positions and then it will check if they are occupied with the same value 'X' or 'O'. Of course, they should be all 'X' or 'O'. boardModule = { boardArray = [ , , , , , , , , ]; gameBoard = .querySelector( ); cells = .from( .querySelectorAll( )); winner = ; render = { boardArray.forEach( { cells[idx].textContent = boardArray[idx]; }); }; reset = { boardArray = [ , , , , , , , , ]; }; checkWin = { winArrays = [ [ , , ], [ , , ], [ , , ], [ , , ], [ , , ], [ , , ], [ , , ], [ , , ], ]; winArrays.forEach( { (boardArray[combo[ ]] && boardArray[combo[ ]] === boardArray[combo[ ]] && boardArray[combo[ ]] === boardArray[combo[ ]]) { winner = ; } }); winner || (boardArray.includes( ) ? : ); }; { render, gameBoard, cells, boardArray, checkWin, reset, }; })(); const ( ) => ( let '' '' '' '' '' '' '' '' '' const document '#board' const Array document '.cell' let null const => () ( ) => mark, idx const => () '' '' '' '' '' '' '' '' '' const => () const 0 1 2 3 4 5 6 7 8 0 3 6 1 4 7 2 5 8 0 4 8 2 4 6 ( ) => combo if 0 0 1 0 2 'current' return '' null 'Tie' return Let's continue to the gamePlay module, which will be the last module. In this module, we will interact with the DOM to get the player names and form. The switchTurn method will switch turns between the players as the name describes. The gameRound method will control of the game round. It will check if there is a winner or if there is a tie. If none of the two happen, it will call the switchTurn method defined above. The gameInit method, which is the only method returned at the end, will initialize the game. gamePlay = { playerOneName = .querySelector( ); playerTwoName = .querySelector( ); form = .querySelector( ); resetBtn = .querySelector( ); currentPlayer; playerOne; playerTwo; switchTurn = { currentPlayer = currentPlayer === playerOne ? playerTwo : playerOne; }; gameRound = { board = boardModule; gameStatus = .querySelector( ); (currentPlayer.name !== ) { gameStatus.textContent = ; } { gameStatus.textContent = ; } board.gameBoard.addEventListener( , (event) => { event.preventDefault(); play = currentPlayer.playTurn(board, event.target); (play !== ) { board.boardArray[play] = ; board.render(); winStatus = board.checkWin(); (winStatus === ) { gameStatus.textContent = ; } (winStatus === ) { switchTurn(); gameStatus.textContent = ; } { gameStatus.textContent = ; board.reset(); board.render(); } } }); }; gameInit = { (playerOneName.value !== && playerTwoName.value !== ) { playerOne = playerFactory(playerOneName.value, ); playerTwo = playerFactory(playerTwoName.value, ); currentPlayer = playerOne; gameRound(); } }; form.addEventListener( , (event) => { event.preventDefault(); (playerOneName.value !== && playerTwoName.value !== ) { gameInit(); form.classList.add( ); .querySelector( ).classList.remove( ); } { .location.reload(); } }); resetBtn.addEventListener( , () => { .querySelector( ).textContent = ; .querySelector( ).value = ; .querySelector( ).value = ; .location.reload(); }); { gameInit, }; })(); const ( ) => ( const document '#player1' const document '#player2' const document '.player-info' const document '#reset' let let let const => () const => () const const document '.game-status' if '' ` 's Turn` ${currentPlayer.name} else 'Board: ' 'click' const if null ` ` ${currentPlayer.mark} const if 'Tie' 'Tie!' else if null ` 's Turn` ${currentPlayer.name} else `Winner is ` ${currentPlayer.name} const => () if '' '' 'X' 'O' 'submit' if '' '' 'hidden' document '.place' 'hidden' else window 'click' document '.game-status' 'Board: ' document '#player1' '' document '#player2' '' window return Finally, we will call the gameInit method. It will initialize the game. We can start playing after this. gamePlay.gameInit(); So now you can enjoy the game. Please follow me on if you like the article. Github