Now Hiring: Are you a driven and motivated 1st Line IT Support Engineer?

Office Hours: 10:00am-6:00pm

 

Call Anytime 24/7

 

Mail Us For Support

 

Office Address

How to Build a Chess Board Game with HTML, CSS & JavaScript (with Move Validation, Timers & More)

  • Home
  • IT Solution
  • How to Build a Chess Board Game with HTML, CSS & JavaScript (with Move Validation, Timers & More)
How to Build a Chess Board Game with HTML, CSS & JavaScript (with Move Validation, Timers & More)

Creating games in the browser is a great way to strengthen your front-end skills. In this tutorial, we’ll walk through building a fully functional Chess game using HTML, CSS, and JavaScript, enhanced with:

  • ♟ Valid Move Logic via chess.js
  • 🎯 Turn-based System
  • 💡 Highlighted Legal Moves
  • 🎵 Sound Effects
  • ⏱ Player Timers
  • 💥 Captured Pieces Display

Whether you’re a beginner looking to sharpen your skills or a seasoned dev exploring game mechanics in JavaScript, this post will guide you step by step.

Prerequisites

To follow along, you should have:

  • A basic understanding of HTML/CSS
  • Intermediate knowledge of JavaScript
  • A code editor (like VS Code)
  • A browser (Chrome/Firefox)

Step 1: Project Setup

Create a new folder and add three files:

/chess-game

  ├── index.html

  ├── style.css

  └── script.js

Step 2: Create the HTML UI (index.html)

This file sets up the structure of the chessboard, timers, captured pieces, and includes the required scripts.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Chess Game</title>
  <link rel="stylesheet" href="style.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/chess.js/0.12.0/chess.min.js"></script>
</head>
<body>
  <h1>Chess Game</h1>

  <div id="info">
    <div id="turn">Turn: White</div>
    <div id="timers">
      <span>White: <span id="white-timer">00:00</span></span>
      <span>Black: <span id="black-timer">00:00</span></span>
    </div>
  </div>

  <div id="captured">
    <div>White Captured: <span id="white-captured"></span></div>
    <div>Black Captured: <span id="black-captured"></span></div>
  </div>

  <div id="chessboard"></div>

  <audio id="moveSound" src="https://www.soundjay.com/button/beep-07.wav" preload="auto"></audio>

  <script src="script.js"></script>
</body>
</html>

Step 3: Style the Chessboard (style.css)

Here’s how we’ll visually structure the board and elements:

body {
  display: flex;
  flex-direction: column;
  align-items: center;
  background: #f5f5f5;
  font-family: sans-serif;
  margin: 0;
  padding: 0;
}

h1 {
  margin: 20px;
}

#info {
  display: flex;
  justify-content: space-between;
  width: 400px;
  margin-bottom: 10px;
}

#timers {
  display: flex;
  gap: 20px;
}

#captured {
  display: flex;
  justify-content: space-around;
  width: 400px;
  margin-bottom: 10px;
}

#chessboard {
  display: grid;
  grid-template-columns: repeat(8, 60px);
  grid-template-rows: repeat(8, 60px);
  border: 2px solid #333;
}

.square {
  width: 60px;
  height: 60px;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 36px;
  cursor: pointer;
}

.white {
  background-color: #f0d9b5;
}

.black {
  background-color: #b58863;
}

.highlight {
  background-color: yellow !important;
}

.piece {
  user-select: none;
}

Step 4: JavaScript Logic (script.js)

Here’s where the magic happens — handling move validation, UI updates, and game logic using chess.js.

const board = document.getElementById('chessboard');
const chess = new Chess();
const moveSound = document.getElementById('moveSound');
const whiteCaptured = document.getElementById('white-captured');
const blackCaptured = document.getElementById('black-captured');
const turnText = document.getElementById('turn');
const whiteTimer = document.getElementById('white-timer');
const blackTimer = document.getElementById('black-timer');

let selectedSquare = null;
let highlightedSquares = [];
let whiteTime = 0;
let blackTime = 0;

// Unicode symbols for pieces
const pieceUnicode = {
  pw: '♙', nw: '♘', bw: '♗', rw: '♖', qw: '♕', kw: '♔',
  pb: '♟', nb: '♞', bb: '♝', rb: '♜', qb: '♛', kb: '♚'
};

// Format seconds into mm:ss
function formatTime(sec) {
  const m = Math.floor(sec / 60).toString().padStart(2, '0');
  const s = (sec % 60).toString().padStart(2, '0');
  return `${m}:${s}`;
}

// Update timers
setInterval(() => {
  if (chess.turn() === 'w') whiteTime++;
  else blackTime++;
  whiteTimer.textContent = formatTime(whiteTime);
  blackTimer.textContent = formatTime(blackTime);
}, 1000);

// Clear move highlights
function clearHighlights() {
  highlightedSquares.forEach(sq => sq.classList.remove('highlight'));
  highlightedSquares = [];
}

// Draw board
function createBoard() {
  board.innerHTML = '';
  clearHighlights();
  const boardArr = chess.board();

  for (let row = 0; row < 8; row++) {
    for (let col = 0; col < 8; col++) {
      const square = document.createElement('div');
      square.classList.add('square');
      square.classList.add((row + col) % 2 === 0 ? 'white' : 'black');
      const file = 'abcdefgh'[col];
      const rank = 8 - row;
      const pos = file + rank;
      square.dataset.position = pos;

      const piece = boardArr[row][col];
      if (piece) {
        const symbol = pieceUnicode[piece.type + piece.color];
        square.textContent = symbol || '';
        square.classList.add('piece');
      }

      square.addEventListener('click', () => handleClick(square, pos));
      board.appendChild(square);
    }
  }

  turnText.textContent = `Turn: ${chess.turn() === 'w' ? 'White' : 'Black'}`;
}

// Handle click on square
function handleClick(square, position) {
  const piece = chess.get(position);

  if (selectedSquare && chess.moves({ square: selectedSquare }).includes(position)) {
    const move = chess.move({ from: selectedSquare, to: position });
    if (move) {
      moveSound.play();

      // Handle captured pieces
      if (move.captured) {
        const capturedSymbol = pieceUnicode[move.captured + (move.color === 'w' ? 'b' : 'w')];
        if (move.color === 'w') {
          blackCaptured.textContent += capturedSymbol;
        } else {
          whiteCaptured.textContent += capturedSymbol;
        }
      }

      selectedSquare = null;
      createBoard();
    }
  } else if (piece && piece.color === chess.turn()) {
    selectedSquare = position;
    clearHighlights();
    const moves = chess.moves({ square: position, verbose: true });
    moves.forEach(m => {
      const sq = document.querySelector(`[data-position='${m.to}']`);
      if (sq) {
        sq.classList.add('highlight');
        highlightedSquares.push(sq);
      }
    });
  } else {
    selectedSquare = null;
    clearHighlights();
  }
}

// Initialize
createBoard();

Features Recap

FeatureDescription
♟ Move ValidationEnforced using chess.js
🔁 Turn LogicAutomatically swaps turns between players
✨ Highlight MovesShows valid moves on click
🕒 TimerReal-time timer for each player
💥 Capture DisplayCaptured pieces shown with Unicode
🔊 SoundSimple move sound on valid move

What’s Next?

Here are some improvements you can add:

  • ♻️ Undo/Redo functionality
  • 🔄 Restart/New Game button
  • 🌐 Multiplayer support via WebSockets
  • 💬 Check/Checkmate alerts
  • 🎨 Responsive/mobile layout

Conclusion

This project is a fantastic example of blending JavaScript game logic with interactive UI to create a complete, playable browser game. By leveraging chess.js for validation and combining HTML/CSS for UI, we built a polished chess game entirely in the browser.

If you found this tutorial helpful, feel free to share it, leave a comment, or suggest the next feature to add!

Leave A Comment

Your email address will not be published. Required fields are marked *