How to build a Tic-Tac-Toe Game using React Hooks ?
Last Updated :
07 Nov, 2023
To build a Tic-Tac-Toe using react Hooks include the interactive components that represent the board, the signs, and at last the winner of the game.
Preview of final output: Let us have a look at how the final application will look like.

Prerequisite of Tic-Tac-Toe Game:
Approach:
To create a Tic-Tac-Toe Game in React js will use the React functional components along with React JS hooks to enable the interaction and store moves. After each move, the component will switch between players and mark X or 0 on selected part the board. Style the game board using CSS for a better appearance.
Steps to Create React Application and Install required modules:Â
Step 1: Use this command in the terminal to initialize the react project.
npx create-react-app tic-tac-toe-react
Step 2: Switch to the tic-tac-toe-react directory using the following command.
cd tic-tac-toe-react
Project Structure:

Example: This example implement react components and css to build a Tic-Tac-Toe game using React Hooks.
JavaScript
// Filename - App.js
// Importing the required components
import Board from "./Board";
import Info from "./Info";
// Importing the CSS File
import "./App.css";
// Importing the useState hook
import { useState } from "react";
function App() {
// Creating a reset state, which indicates whether
// the game should be reset or not
const [reset, setReset] = useState(false);
// Creating a winner state, which indicates
// the current winner
const [winner, setWinner] = useState("");
// Sets the reset property to true
// which starts the chain
// reaction of resetting the board
const resetBoard = () => {
setReset(true);
};
return (
<div className="App">
{/* Shrinks the popup when there is no winner */}
<div
className={`winner ${
winner !== "" ? "" : "shrink"
}`}
>
{/* Display the current winner */}
<div className="winner-text">{winner}</div>
{/* Button used to reset the board */}
<button onClick={() => resetBoard()}>
Reset Board
</button>
</div>
{/* Custom made board component comprising of
the tic-tac-toe board */}
<Board
reset={reset}
setReset={setReset}
winner={winner}
setWinner={setWinner}
/>
<Info />
</div>
);
}
export default App;
JavaScript
// Filename - Board.js
// Importing the CSS for the board
import "./css/board.css";
// Importing the useState hook, useEffect hook and useRef hook
import { useState, useEffect, useRef } from "react";
const Board = ({ reset, setReset, winner, setWinner }) => {
// Creating a turn state, which indicates the current turn
const [turn, setTurn] = useState(0);
// Creating a data state, which contains the
// current picture of the board
const [data, setData] = useState([
"",
"",
"",
"",
"",
"",
"",
"",
"",
]);
// Creating a reference for the board
const boardRef = useRef(null);
// Function to draw on the board
const draw = (event, index) => {
// Draws only if the position is not taken
// and winner is not decided yet
if (data[index - 1] === "" && winner === "") {
// Draws X if it's player 1's turn else draws O
const current = turn === 0 ? "X" : "O";
// Updating the data state
data[index - 1] = current;
//Drawing on the board
event.target.innerText = current;
// Switching the turn
setTurn(turn === 0 ? 1 : 0);
}
};
// UseEffect hook used to reset the board whenever
// a winner is decided
useEffect(() => {
// Clearing the data state
setData(["", "", "", "", "", "", "", "", ""]);
// Getting all the children(cells) of the board
const cells = boardRef.current.children;
// Clearing out the board
for (let i = 0; i < 9; i++) {
cells[i].innerText = "";
}
// Resetting the turn to player 0
setTurn(0);
// Resetting the winner
setWinner("");
setReset(false);
}, [reset, setReset, setWinner]);
// useEffect hook used to check for a winner
useEffect(() => {
// Checks for the win condition in rows
const checkRow = () => {
let ans = false;
for (let i = 0; i < 9; i += 3) {
ans |=
data[i] === data[i + 1] &&
data[i] === data[i + 2] &&
data[i] !== "";
}
return ans;
};
// Checks for the win condition in cols
const checkCol = () => {
let ans = false;
for (let i = 0; i < 3; i++) {
ans |=
data[i] === data[i + 3] &&
data[i] === data[i + 6] &&
data[i] !== "";
}
return ans;
};
// Checks for the win condition in diagonals
const checkDiagonal = () => {
return (
(data[0] === data[4] &&
data[0] === data[8] &&
data[0] !== "") ||
(data[2] === data[4] &&
data[2] === data[6] &&
data[2] !== "")
);
};
// Checks if at all a win condition is present
const checkWin = () => {
return (
checkRow() || checkCol() || checkDiagonal()
);
};
// Checks for a tie
const checkTie = () => {
let count = 0;
data.forEach((cell) => {
if (cell !== "") {
count++;
}
});
return count === 9;
};
// Setting the winner in case of a win
if (checkWin()) {
setWinner(
turn === 0
? "Player 2 Wins!"
: "Player 1 Wins!"
);
} else if (checkTie()) {
// Setting the winner to tie in case of a tie
setWinner("It's a Tie!");
}
});
return (
<div ref={boardRef} className="board">
<div
className="input input-1"
onClick={(e) => draw(e, 1)}
></div>
<div
className="input input-2"
onClick={(e) => draw(e, 2)}
></div>
<div
className="input input-3"
onClick={(e) => draw(e, 3)}
></div>
<div
className="input input-4"
onClick={(e) => draw(e, 4)}
></div>
<div
className="input input-5"
onClick={(e) => draw(e, 5)}
></div>
<div
className="input input-6"
onClick={(e) => draw(e, 6)}
></div>
<div
className="input input-7"
onClick={(e) => draw(e, 7)}
></div>
<div
className="input input-8"
onClick={(e) => draw(e, 8)}
></div>
<div
className="input input-9"
onClick={(e) => draw(e, 9)}
></div>
</div>
);
};
export default Board;
JavaScript
// Filename - Info.js
// Importing the css for the info
import "./css/info.css";
const Info = () => {
return (
<div className="info">
<div className="player">Player 1: X</div>
<div className="player">Player 2: O</div>
</div>
);
};
export default Info;
CSS
/* index.css */
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont,
"Segoe UI", "Roboto", "Oxygen", "Ubuntu",
"Cantarell", "Fira Sans", "Droid Sans",
"Helvetica Neue", sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas,
"Courier New", monospace;
}
CSS
/* Filename - App.css */
@import url(
"https://fonts.googleapis.com/css2?family=Bellefair&display=swap"
);
.App {
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
gap: 5vh;
backdrop-filter: 5px;
background-color: #101010;
}
.winner {
transition: all ease-in 0.3s;
display: flex;
opacity: 1;
font-size: 1.5rem;
font-weight: 600;
gap: 1vh;
flex-direction: column;
justify-content: center;
align-items: center;
width: 20vw;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -70%);
background-color: rgba(195, 141, 158, 0.863);
backdrop-filter: 5px;
padding: 0.5rem;
padding-bottom: 1rem;
border-radius: 10%;
}
.winner-text {
padding: 0.3em 1em 0.25em;
font-weight: 600;
font-size: 2.5rem;
color: white;
font-family: "Bellefair", serif;
position: relative;
text-align: center;
line-height: 1.3;
}
.shrink {
transform: scale(0.1);
opacity: 0;
}
button {
background-color: #111827;
border: 1px solid transparent;
border-radius: 0.75rem;
box-sizing: border-box;
color: #ffffff;
cursor: pointer;
flex: 0 0 auto;
font-family: "Inter var";
font-size: 1.125rem;
font-weight: 600;
line-height: 1.5rem;
padding: 0.75rem 1.2rem;
text-align: center;
text-decoration: none #6b7280 solid;
text-decoration-thickness: auto;
transition-duration: 0.2s;
transition-property: background-color, border-color,
color, fill, stroke;
transition-timing-function: cubic-bezier(
0.4,
0,
0.2,
1
);
user-select: none;
-webkit-user-select: none;
touch-action: manipulation;
width: auto;
}
button:hover {
background-color: #374151;
}
button:focus {
box-shadow: none;
outline: 2px solid transparent;
outline-offset: 2px;
}
@media (min-width: 768px) {
button {
padding: 0.75rem 1.5rem;
}
}
CSS
/* Filename - css/info.css */
.info {
width: 30vw;
display: flex;
justify-content: space-evenly;
align-items: center;
color: whitesmoke;
}
.player {
border: 2px solid #f6546a;
border-radius: 5%;
padding: 0.5rem 0;
display: flex;
font-size: 1.5rem;
justify-content: center;
align-items: center;
width: 10vw;
}
CSS
/* Filename - css/board.css */
:root {
--board-background: none;
--border-color: #f6546a;
--border-thickness: 5px;
}
.board {
width: 30vw;
height: 50%;
background-color: var(--board-background);
display: flex;
align-items: flex-start;
flex-direction: row;
flex-wrap: wrap;
}
.input {
height: 33.33%;
width: 33.33%;
display: flex;
justify-content: center;
align-items: center;
color: whitesmoke;
font-family: "Bellefair", serif;
font-style: italic;
font-weight: 700;
font-size: 6rem;
}
.input-1 {
border-right: var(--border-thickness) dashed
var(--border-color);
border-bottom: var(--border-thickness) dashed
var(--border-color);
}
.input-2 {
border-right: var(--border-thickness) dashed
var(--border-color);
border-bottom: var(--border-thickness) dashed
var(--border-color);
}
.input-3 {
border-bottom: var(--border-thickness) dashed
var(--border-color);
}
.input-4 {
border-right: var(--border-thickness) dashed
var(--border-color);
border-bottom: var(--border-thickness) dashed
var(--border-color);
}
.input-5 {
border-right: var(--border-thickness) dashed
var(--border-color);
border-bottom: var(--border-thickness) dashed
var(--border-color);
}
.input-6 {
border-bottom: var(--border-thickness) dashed
var(--border-color);
}
.input-7 {
border-right: var(--border-thickness) dashed
var(--border-color);
}
.input-8 {
border-right: var(--border-thickness) dashed
var(--border-color);
}
Steps to Run the Application:Use this command in the terminal inside the project directory.
npm start
Output: This output will be visible on http://localhost:3000/ on the browser window.

Similar Reads
Multiplayer Tic Tac Toe Game using React & Node This project is a Multiplayer Online Tic Tac Toe game developed using React & NodeJS . It allows multiple users to play the classic Tic Tac Toe game in real time. The application handles basic and advanced calculations related to the game logic and ensures a smooth gaming experience. Output Prev
6 min read
Create a Tic-Tac-Toe using React-Native In this article, we will learn how to build a Tic-Tac-Toe game using React-Native. React Native enables the application to run a single code base on multiple platforms like Android, IOS, etc. Developing the TicTacToe game application allows us to learn basic styling, app logic, user interaction, and
4 min read
How to generate random colors by using React hooks ? In web development, colors play a vital role in creating visually appealing and engaging user interfaces. In React we may need to generate random colors dynamically. In this article, we will explore how to achieve this using React hooks, a powerful feature introduced in ReactJs. Pre-requisite:NPM
2 min read
How to Use ES6 Map with React State Hooks? In JavaScript, the Map object is a collection of key-value pairs, where keys can be of any data type. In React, managing such key-value pairs with hooks like useState can simplify handling dynamic data structures. Reactâs state management system allows for smooth and efficient data manipulation, mak
6 min read
Building a Tooltip Component with React Hooks Building a Tooltip Component with React Hooks is straightforward and effective. Tooltips are a common UI element used to provide additional information when a user hovers over or focuses on an element. In this article, we'll build a Tooltip component using React Hooks. PrerequisitesNPM & NodeJSR
3 min read