Minesweeper Game — Free HTML CSS JS Snippet

Minesweeper Puzzle Game · Games · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Iterative stack-based floodReveal() flood fill, avoiding recursion depth issues on cascading reveals
Mine placement deferred until after the first click via placeMines(excludeR, excludeC) for guaranteed-fair openings
countAdjacentMines() precomputes the classic 3x3 neighbour scan for every non-mine cell
Colour-coded number classes .n1 through .n8 matching the traditional Minesweeper convention
Dual flagging input: contextmenu event for right-click desktop flagging plus a touch-friendly flag-mode toggle
Live mine counter (mines minus flags) and a setInterval-driven timer capped at 999 seconds
revealAllMines() highlights the exact mine that ended the game with a distinct .mine-triggered class
Win detection by comparing revealedCount against the precomputed safe-cell total, auto-flagging remaining mines on victory

About this UI Snippet

Minesweeper Puzzle Game — Recursive Flood Fill, Safe First-Click Generation & Flag Logic

Screenshot of the Minesweeper Puzzle Game snippet rendered live

Minesweeper is one of the oldest and most instructive logic puzzles to implement, because a correct version is not just a grid of clickable squares — it requires a genuine flood-fill algorithm, deferred board generation, and careful state tracking for flags, reveals, and win detection. This snippet builds a fully playable 9x9 grid with 10 mines using nothing but vanilla JavaScript and CSS Grid, and every rule that makes Minesweeper feel fair and satisfying is implemented rather than faked.

Safe first click, generated after the fact

The classic frustration in a badly made Minesweeper clone is losing on your very first click through no fault of your own. This snippet avoids that entirely: the board starts completely empty of mines, and placeMines(excludeR, excludeC) only runs the moment the player clicks their first cell, deliberately skipping that cell and its eight neighbours when scattering the 10 mines with Math.random(). This guarantees the opening click always lands on a safe, typically zero-adjacency area, which is the standard fairness convention every reference implementation of Minesweeper follows.

Iterative flood fill, not a single-cell reveal

Clicking a cell with zero adjacent mines should cascade outward and reveal every connected empty region along with its numbered border — this is the heart of what makes Minesweeper fun to play quickly. The floodReveal() function implements this with an explicit stack rather than naive recursion (which risks call-stack depth issues on larger boards): it pushes the starting cell, pops cells one at a time, marks each revealed, and — only when that cell's adjacent count is zero — pushes all eight unrevealed neighbours back onto the stack. Cells with a positive adjacency count are still revealed and rendered with their colour-coded number, but the fill does not continue past them, exactly matching the classic Windows Minesweeper behaviour.

Colour-coded numbers and flag mode

Revealed cells with adjacent mines get a class like .n3 that maps to the traditional colour convention — 1 is blue, 2 is green, 3 is red, and so on up through 8 — purely through CSS class selectors keyed off the stored adjacent integer. Flagging is handled two ways: a right-click (contextmenu event, with preventDefault() to suppress the browser menu) toggles a flag on desktop, while a dedicated "Flag mode" toggle button lets touch users tap to flag instead of reveal, since touch devices have no reliable right-click equivalent.

Win and loss detection

Every reveal increments a revealedCount counter; the game is won the instant that count equals the total non-mine cell count (81 minus 10 mines), which is checked after every successful reveal in checkWin(). Losing triggers revealAllMines(), which reveals every mine on the board and highlights the specific one that was clicked in a brighter red so the player can see exactly what ended the round. A live mine counter subtracts placed flags from the total mine count, and a timer starts on the first click and stops the instant the game ends, both rendered in a retro seven-segment style display for authenticity.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to trace exactly how floodReveal()'s stack-based traversal decides which neighbouring cells to push, and why it stops expanding past a numbered cell but not past a zero-adjacency one — understanding that boundary condition is the key to understanding the whole algorithm. It's also a great snippet to extend with AI help: ask it to add a difficulty selector that swaps ROWS/COLS/MINES and resizes the CSS grid to match, add a chording feature (clicking a revealed number that already has the correct number of adjacent flags reveals all its remaining unflagged neighbours), or persist best completion times per difficulty using localStorage the same way the 2048 snippet in this gallery persists its best score. Treat the working game as a base to question and build on, not a finished black box.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a playable Minesweeper game in plain HTML, CSS, and JavaScript on a 9x9 grid with 10 mines — no frameworks, no libraries.

Requirements:
- Mines must not be placed until after the player's first click, and that first click (plus its immediate neighbours) must never be a mine, so the opening move is always safe.
- Clicking a cell with zero adjacent mines must cascade-reveal all connected zero-adjacency cells and their bordering numbered cells using a real flood-fill algorithm (iterative or recursive), not just the single clicked cell.
- Revealed cells with adjacent mines must show the count, colour-coded using the classic convention (1 blue, 2 green, 3 red, etc).
- Right-click must flag a hidden cell instead of revealing it, and there must be a separate flag-mode toggle so touch-only users without a right-click can flag cells too.
- Track and display a live mine counter (total mines minus flags currently placed) and a timer that starts on the first click and stops when the game ends.
- Clicking a mine must end the game immediately, reveal every mine on the board, and visually distinguish the specific mine that was clicked from the rest.
- Detect the win condition (every non-mine cell revealed) and show a distinct win state, and provide a button to start a completely fresh game with a newly randomized mine layout at any time.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Reveal your first cellClick any cell on the 9x9 grid. Mines are generated only after this first click, and the clicked cell plus its neighbours are guaranteed mine-free, so your opening move is always safe.
  2. 2
    Read the flood-fill revealIf the clicked cell has zero adjacent mines, floodReveal() cascades outward and automatically reveals the whole connected empty region plus its numbered border cells, exactly like the classic game.
  3. 3
    Flag suspected minesRight-click a hidden cell to place a flag on desktop. On touch devices, tap the "Flag mode" toggle button first, then tap cells to flag them instead of revealing them.
  4. 4
    Watch the counter and timerThe left digital counter shows mines remaining (10 minus flags placed) and the right counter is a timer that starts on your first click and freezes the instant the round ends.
  5. 5
    Win or lose the roundClicking a mine ends the game immediately and reveals every mine, with the fatal one highlighted in bright red. Revealing all 71 safe cells triggers the win state and auto-flags the remaining mines.
  6. 6
    Start a new gameClick the face button (🙂) at any time — it shows 😎 on a win or 💀 on a loss — to instantly regenerate a fresh empty board and reset the counter, timer, and flag mode.

Real-world uses

Common Use Cases

Teaching flood-fill and graph traversal concepts
Minesweeper's cascading reveal is one of the most approachable real-world examples of a flood-fill / connected-component search, the same family of algorithm behind the bucket-fill tool in image editors and connected-region detection in computer vision. This snippet's iterative stack-based implementation is a clean teaching example for students learning breadth-first or depth-first traversal without the overhead of recursion.
Portfolio and coding-interview showpiece
A working Minesweeper clone is a well-recognised way to demonstrate state management, 2D grid algorithms, and DOM performance in a portfolio project or take-home interview exercise. Because every rule — safe first click, flood fill, flagging, win/loss detection — is implemented rather than mocked, it holds up to detailed code review far better than a static grid mockup.
Idle-moment browser game embedded in a site
Drop this into a 404 page, a changelog page, or a "just for fun" section of a personal site or internal tool to give visitors something genuinely playable while they wait or browse. Its self-contained HTML/CSS/JS with no dependencies makes it trivial to embed anywhere a spare corner of screen space exists.
Retro digital-counter and grid UI reference
The seven-segment-style mine and timer counters, the face button micro-interactions, and the neutral grid palette with a single accent colour are a reusable reference for building other retro-styled utility widgets, dashboards, or arcade-style UI elements that need a nostalgic digital-display aesthetic.
Base for a difficulty-selectable or timed-challenge variant
Because ROWS, COLS, and MINES are top-level constants, this snippet is a natural starting point for adding a difficulty selector (Beginner 9x9/10, Intermediate 16x16/40, Expert 30x16/99) or a leaderboard that stores best completion times in localStorage, similar in spirit to the persisted best-score pattern used in the 2048 Tile Merge Puzzle snippet.
Accessible touch-first mobile puzzle
Because right-click has no reliable equivalent on touch screens, the explicit "Flag mode" toggle button gives mobile and tablet users full parity with desktop play — a pattern worth reusing anywhere a desktop app relies on a secondary mouse button for an action that touch users also need to perform.

Got questions?

Frequently Asked Questions

Mines are not placed when the board is first built — the grid starts completely empty. placeMines(r, c) only runs inside handleCellClick() the moment you make your first click, and it explicitly skips the clicked cell plus its eight surrounding neighbours when scattering the 10 mines. This "safe first click" rule is the standard fairness convention in every well-made Minesweeper implementation, including Microsoft's original.

floodReveal() only ever pushes unrevealed, unflagged neighbour cells onto its stack, and it stops expanding outward from any cell whose adjacent mine count is greater than zero — it still reveals that numbered cell but does not continue past it. Since mines are never popped from the stack (the function is only ever called starting from a confirmed non-mine cell), a correct board layout guarantees the cascade can never touch a mine cell.

Yes. The ROWS, COLS, and MINES constants at the top of the JS control the entire board. Increasing MINES relative to the grid area raises difficulty; the CSS grid-template-columns/rows on .ms-board must be updated to match COLS and ROWS if you change them, since the layout is not currently computed dynamically from those constants.

Each .ms-cell is rendered as a real <button>, so it is already focusable and clickable via Enter/Space by default. For fuller accessibility, add arrow-key navigation between grid cells using a roving tabindex pattern, and add aria-label attributes reflecting each cell's state (hidden, flagged, revealed-with-count, or mine) so screen reader users get equivalent information to the visual number colours and flag icon.

A naive recursive flood fill calls itself once per revealed cell, and on a large, mostly-empty board that can produce thousands of nested calls, risking a "Maximum call stack size exceeded" error in some browsers. The iterative version in this snippet uses a plain JavaScript array as an explicit stack, achieving the identical reveal pattern without any risk of stack overflow, which matters more as you scale the grid up from the default 9x9 to Expert-sized 30x16 boards.