Build a Tic-Tac-Toe Web App

CSSCSSBeginner
Practice Now

Introduction

In this project, you will learn how to create a Tic-Tac-Toe game using HTML, CSS, and JavaScript. Tic-Tac-Toe is a two-player game where players take turns marking X or O in a 3x3 grid. The objective is to get three marks in a row, either horizontally, vertically, or diagonally. You will create the necessary HTML, CSS, and JavaScript files and implement the game logic step by step.

👀 Preview

Alt text

🎯 Tasks

In this project, you will learn:

  • How to set up the basic structure of the Tic-Tac-Toe game using HTML.
  • How to add CSS styles to define the appearance of the game elements.
  • How to implement the game logic using JavaScript.
  • How to handle user interactions, check for wins or ties, and update scores.
  • How to render the game board and update the turn indicator.
  • How to allow players to reset the game and start a new round.

🏆 Achievements

After completing this project, you will be able to:

  • Structure an HTML file for a web application.
  • Style elements using CSS classes.
  • Implement game logic using JavaScript.
  • Handle user interactions and update the UI accordingly.
  • Render the game board and update the turn indicator.
  • Create event listeners and handle events in JavaScript.

Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL css(("`CSS`")) -.-> css/BasicConceptsGroup(["`Basic Concepts`"]) css(("`CSS`")) -.-> css/BasicStylingGroup(["`Basic Styling`"]) css(("`CSS`")) -.-> css/CoreLayoutGroup(["`Core Layout`"]) css(("`CSS`")) -.-> css/AdvancedLayoutGroup(["`Advanced Layout`"]) css(("`CSS`")) -.-> css/IntermediateStylingGroup(["`Intermediate Styling`"]) css(("`CSS`")) -.-> css/CSSPreprocessorsGroup(["`CSS Preprocessors`"]) html(("`HTML`")) -.-> html/BasicStructureGroup(["`Basic Structure`"]) html(("`HTML`")) -.-> html/TextContentandFormattingGroup(["`Text Content and Formatting`"]) html(("`HTML`")) -.-> html/LayoutandSectioningGroup(["`Layout and Sectioning`"]) javascript(("`JavaScript`")) -.-> javascript/BasicConceptsGroup(["`Basic Concepts`"]) javascript(("`JavaScript`")) -.-> javascript/AdvancedConceptsGroup(["`Advanced Concepts`"]) javascript(("`JavaScript`")) -.-> javascript/DOMManipulationGroup(["`DOM Manipulation`"]) javascript(("`JavaScript`")) -.-> javascript/ToolsandEnvironmentGroup(["`Tools and Environment`"]) javascript(("`JavaScript`")) -.-> javascript/SecurityGroup(["`Security`"]) css/BasicConceptsGroup -.-> css/selectors("`Selectors`") css/BasicStylingGroup -.-> css/colors("`Colors`") css/BasicStylingGroup -.-> css/fonts("`Fonts`") css/BasicStylingGroup -.-> css/text_styling("`Text Styling`") css/CoreLayoutGroup -.-> css/box_model("`Box Model`") css/CoreLayoutGroup -.-> css/margin_and_padding("`Margin and Padding`") css/CoreLayoutGroup -.-> css/borders("`Borders`") css/CoreLayoutGroup -.-> css/width_and_height("`Width and Height`") css/CoreLayoutGroup -.-> css/display_property("`Display Property`") css/AdvancedLayoutGroup -.-> css/flexbox("`Flexbox`") css/AdvancedLayoutGroup -.-> css/grid_layout("`Grid Layout`") css/IntermediateStylingGroup -.-> css/backgrounds("`Backgrounds`") css/CSSPreprocessorsGroup -.-> css/mixins("`Mixins`") css/CSSPreprocessorsGroup -.-> css/nesting("`Nesting`") css/CSSPreprocessorsGroup -.-> css/import_and_extend("`Import and Extend`") html/BasicStructureGroup -.-> html/basic_elems("`Basic Elements`") html/BasicStructureGroup -.-> html/charset("`Character Encoding`") html/BasicStructureGroup -.-> html/lang_decl("`Language Declaration`") html/BasicStructureGroup -.-> html/viewport("`Viewport Declaration`") html/BasicStructureGroup -.-> html/head_elems("`Head Elements`") html/TextContentandFormattingGroup -.-> html/text_head("`Text and Headings`") html/LayoutandSectioningGroup -.-> html/doc_flow("`Document Flow Understanding`") css/IntermediateStylingGroup -.-> css/pseudo_classes("`Pseudo-classes`") javascript/BasicConceptsGroup -.-> javascript/variables("`Variables`") javascript/BasicConceptsGroup -.-> javascript/data_types("`Data Types`") javascript/BasicConceptsGroup -.-> javascript/arith_ops("`Arithmetic Operators`") javascript/BasicConceptsGroup -.-> javascript/comp_ops("`Comparison Operators`") javascript/BasicConceptsGroup -.-> javascript/cond_stmts("`Conditional Statements`") javascript/BasicConceptsGroup -.-> javascript/loops("`Loops`") javascript/BasicConceptsGroup -.-> javascript/functions("`Functions`") javascript/BasicConceptsGroup -.-> javascript/array_methods("`Array Methods`") javascript/BasicConceptsGroup -.-> javascript/obj_manip("`Object Manipulation`") javascript/AdvancedConceptsGroup -.-> javascript/template_lit("`Template Literals`") javascript/DOMManipulationGroup -.-> javascript/dom_select("`DOM Selection`") javascript/DOMManipulationGroup -.-> javascript/dom_manip("`DOM Manipulation`") javascript/DOMManipulationGroup -.-> javascript/event_handle("`Event Handling`") javascript/ToolsandEnvironmentGroup -.-> javascript/bom("`Browser Object Model`") javascript/SecurityGroup -.-> javascript/web_sec("`Web Security Basics`") subgraph Lab Skills css/selectors -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} css/colors -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} css/fonts -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} css/text_styling -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} css/box_model -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} css/margin_and_padding -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} css/borders -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} css/width_and_height -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} css/display_property -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} css/flexbox -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} css/grid_layout -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} css/backgrounds -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} css/mixins -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} css/nesting -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} css/import_and_extend -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} html/basic_elems -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} html/charset -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} html/lang_decl -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} html/viewport -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} html/head_elems -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} html/text_head -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} html/doc_flow -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} css/pseudo_classes -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} javascript/variables -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} javascript/data_types -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} javascript/arith_ops -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} javascript/comp_ops -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} javascript/cond_stmts -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} javascript/loops -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} javascript/functions -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} javascript/array_methods -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} javascript/obj_manip -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} javascript/template_lit -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} javascript/dom_select -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} javascript/dom_manip -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} javascript/event_handle -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} javascript/bom -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} javascript/web_sec -.-> lab-298928{{"`Build a Tic-Tac-Toe Web App`"}} end

Create the HTML File

Create a new file named index.html and add the following code to it.

cd ~/project
touch index.html

This code sets up the basic structure of the Tic-Tac-Toe game.

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Tic-Tac-Toe</title>
    <link
      href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css"
      rel="stylesheet"
    />
    <style>
      /* CSS styles for the game */
    </style>
  </head>

  <body>
    <div id="app">
      <h1 class="text-3xl font-bold mb-4 text-gray-900">Tic-Tac-Toe</h1>
      <div id="board" class="grid grid-cols-3 gap-4 mb-4">
        <!-- Game board cells -->
      </div>
      <div id="scoreboard" class="flex justify-between items-center mb-4">
        <!-- Player scores -->
      </div>
      <div
        id="turn-indicator"
        class="text-2xl font-bold mb-4 text-gray-900"
      ></div>
      <button
        id="reset-button"
        class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
      >
        Reset Game
      </button>
    </div>

    <script>
      // JavaScript code for the game logic
    </script>
  </body>
</html>

Add CSS Styles

Inside the <style> tag in the <head> section of the HTML file, add the CSS styles required for the game. These styles define the appearance of the game elements such as the game board, cells, scores, and buttons.

<style>
  .board-cell {
    width: 100px;
    height: 100px;
  }

  body {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100vh;
    background-color: #222;
    font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
  }

  #app {
    text-align: center;
    background-color: #f5f5f5;
    border-radius: 8px;
    padding: 24px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
  }

  h1 {
    font-size: 32px;
    color: #333;
  }

  .text-gray-900 {
    color: #333 !important;
  }

  .text-2xl {
    font-size: 24px;
  }

  .bg-blue-500 {
    background-color: #4267b2;
  }

  .bg-blue-500:hover {
    background-color: #3b5ca0;
  }

  .bg-blue-700 {
    background-color: #385898;
  }

  .text-white {
    color: #fff !important;
  }

  .rounded {
    border-radius: 4px;
  }

  .highlight {
    background-color: #ffed4a;
  }
</style>

You can also add style.css to the project and link it to the HTML file using the <link> tag.

<link rel="stylesheet" href="style.css" />

Choose whichever method you prefer.

Add Game Logic JavaScript Code

Inside the <script> tag at the end of the HTML file, add the JavaScript code that handles the game logic. This code keeps track of the game state, handles user interactions, checks for a win or a tie, updates scores, and renders the game board.

<script>
  // Game logic code
</script>

Initialize Game Variables

Declare the necessary variables at the beginning of the JavaScript code. These variables will store the game state, player scores, and other relevant information.

// Game logic
const board = ["", "", "", "", "", "", "", "", ""];
let currentPlayer = "X";
let gameEnded = false;
let playerXScore = 0;
let playerOScore = 0;
let winningCells = [];

Handle Cell Click

Create a function named handleCellClick that will be called when a cell on the game board is clicked. This function will handle the main game logic, such as updating the board, checking for a win, updating scores, and changing the current player.

function handleCellClick(index) {
  if (gameEnded || board[index] !== "") return;
  board[index] = currentPlayer;
  renderBoard();

  if (checkWin()) {
    updateScore();
    highlightWinningCells();
    alert(`Player ${currentPlayer} wins!`);
    gameEnded = true;
  } else if (board.every((cell) => cell !== "")) {
    alert("It's a tie!");
    gameEnded = true;
  } else {
    currentPlayer = currentPlayer === "X" ? "O" : "X";
    updateTurnIndicator();
  }
}

Check for a Win

Create a function named checkWin that checks if there is a win condition on the game board. This function compares the values in the board array with the winning combinations to determine if a player has won the game.

function checkWin() {
  const winningCombinations = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6]
  ];

  for (let i = 0; i < winningCombinations.length; i++) {
    const [a, b, c] = winningCombinations[i];
    if (board[a] !== "" && board[a] === board[b] && board[a] === board[c]) {
      winningCells = [a, b, c];
      return true;
    }
  }
  return false;
}

Reset the Game

Create a function named resetGame that resets the game state to its initial values. This function is called when the reset button is clicked and clears the board, resets the current player, clears the winning cells, updates the turn indicator, and renders the board.

function resetGame() {
  board.fill("");
  currentPlayer = "X";
  gameEnded = false;
  winningCells = [];
  updateTurnIndicator();
  renderBoard();
}

Update Player Scores

Create a function named updateScore that updates the scores of the players. This function is called when a player wins a game. It increments the score of the corresponding player and updates the score display on the page.

function updateScore() {
  if (currentPlayer === "X") {
    playerXScore++;
    document.getElementById("player-x-score").textContent = playerXScore;
  } else {
    playerOScore++;
    document.getElementById("player-o-score").textContent = playerOScore;
  }
}

Update Turn Indicator

Create a function named updateTurnIndicator that updates the turn indicator on the page to show the current player's turn.

function updateTurnIndicator() {
  const turnIndicator = document.getElementById("turn-indicator");
  turnIndicator.textContent = `Current Turn: Player ${currentPlayer}`;
}

Highlight Winning Cells

Create a function named highlightWinningCells that adds a highlight class to the winning cells on the game board. This function is called when a player wins the game.

function highlightWinningCells() {
  const cells = document.querySelectorAll(".board-cell");
  cells.forEach((cell, index) => {
    if (winningCells.includes(index)) {
      cell.classList.add("highlight");
    }
  });
}

Render the Game Board

Create a function named renderBoard that updates the game board on the page according to the current state of the board array. This function is called after each player's move to update the visuals.

function renderBoard() {
  const cells = document.querySelectorAll(".board-cell");
  cells.forEach((cell, index) => {
    cell.textContent = board[index];
    cell.classList.remove("highlight");
  });
}

Add Event Listeners

Add event listeners to the game board cells and the reset button. These event listeners call the corresponding functions when the events occur.

// Event listeners
const cells = document.querySelectorAll(".board-cell");
cells.forEach((cell, index) => {
  cell.addEventListener("click", () => handleCellClick(index));
});

const resetButton = document.getElementById("reset-button");
resetButton.addEventListener("click", resetGame);

Initial Render

At the end of the JavaScript code, add the code for the initial render. This code sets up the initial state of the game, updates the turn indicator, and renders the game board.

// Initial render
updateTurnIndicator();
renderBoard();

Run the Project

You can now run the project and play Tic-Tac-Toe!

Click on Go Live button in the bottom right corner of WebIDE, to run the project.

Alt text

This will open the project in Web 8080 Tab.

Alt text

Click on the cells to make your moves and click the reset button to start a new game.

Summary

Congratulations! You have successfully created a Tic-Tac-Toe game using HTML, CSS, and JavaScript. The project covered creating the HTML file, adding CSS styles, implementing the game logic, and handling user interactions. The game allows two players to take turns, checks for a win or a tie, updates scores, and highlights winning cells. You can now run the project and enjoy playing Tic-Tac-Toe!

Other CSS Tutorials you may like