Hangman Word Guessing Game — Free HTML CSS JS Snippet

Hangman Word Guessing Game · Games · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Layered SVG gallows: 7 pre-drawn .hm-part elements toggled visible one at a time via PART_ORDER lookup
Set-based guessed-letter tracking: O(1) has() lookups prevent duplicate guesses and reveal repeated letters at once
Dual input handling: on-screen keyboard clicks and physical keydown events share one guessLetter() function
Disabled-state keyboard: guessed keys get disabled plus .correct/.wrong classes so used letters are visually inert
MAX_WRONG constant of 7: matches the 7 visible-after-frame body parts, easy to retune game difficulty
Word-complete detection: every unique character checked against guessedLetters via Array.every()
Forced full reveal on loss: revealWordFully() shows the answer regardless of what was guessed
CSS opacity transition reveal: each gallows part fades in over 0.25s rather than popping in abruptly

About this UI Snippet

Hangman Word Guessing Game — SVG Gallows Reveal, On-Screen Keyboard & Word State Machine

Screenshot of the Hangman Word Guessing Game snippet rendered live

Hangman is one of the oldest word-guessing games, and its core mechanic translates cleanly into a small, self-contained state machine: a hidden word, a limited number of wrong guesses, and a visual penalty that escalates with every mistake. This snippet builds a fully playable version with a real SVG-drawn gallows figure that reveals one new body part per wrong guess, a clickable on-screen QWERTY keyboard, and full physical-keyboard support, all driven by a small set of JavaScript functions with no external word-guessing library.

The gallows as layered, pre-drawn SVG

Rather than drawing the hangman figure with JavaScript canvas calls or swapping image files, the entire gallows and figure are pre-drawn once as a single SVG containing eight separate shape elements: the gallows post and beam (always visible), then seven body-part elements — the rope, head, body, both arms, and both legs — each given the class hm-part and starting at opacity: 0. A PART_ORDER array in JavaScript lists these seven part class names in the exact sequence they should appear. Every time a wrong guess is made, revealBodyPart(wrongCount - 1) looks up the next class name in that array and adds a .show class, which flips opacity to 1 with a CSS transition. This means the entire drawing logic is just an array index lookup plus a class toggle — no path recalculation, no redraw, and the reveal animation is handled entirely by the CSS transition: opacity 0.25s ease rule.

Word state and letter-slot rendering

The secret word is chosen once per game with WORDS[Math.floor(Math.random() * WORDS.length)] from a small hardcoded word list, and correctly-guessed letters are tracked in a Set called guessedLetters — a Set is used specifically because it gives O(1) has() lookups and naturally prevents duplicate guesses from being counted twice. renderWord() rebuilds the row of letter slots on every guess: it iterates each character of the secret word and, for characters present in guessedLetters, renders the actual letter with a .revealed class that switches its underline to the accent colour; otherwise it renders an underscore placeholder. Because a Set lookup is used rather than tracking revealed positions directly, a single correct guess of a repeated letter (for example guessing "A" in "GALAXY") reveals every occurrence of that letter simultaneously, exactly as the physical game works.

Dual input: on-screen keyboard and real keyboard

The on-screen keyboard is generated programmatically by looping character codes 65 through 90 (A-Z) and creating one button per letter, each wired to guessLetter(letter) via addEventListener. A parallel keydown listener on document normalises e.key to uppercase and, if it is a single A-Z character, calls the exact same guessLetter() function — so physical typing and on-screen clicking share one code path with no duplicated logic. Once a letter has been guessed, its corresponding button gets disabled = true plus either a .correct (green) or .wrong (red) class, which both greys it out via reduced opacity and blocks further clicks or accidental re-guesses of the same letter from the keyboard listener, since guessedLetters.has(letter) short-circuits guessLetter() at the top.

Win and loss detection

After every guess, checkGameEnd() runs two checks: [...secretWord].every(ch => guessedLetters.has(ch)) tests whether every unique character in the word has been guessed (a win), and wrongCount >= MAX_WRONG (set to 7, matching the seven gallows parts revealed after the always-visible frame) tests for a loss. On a loss, revealWordFully() forcibly renders every letter of the secret word regardless of what was guessed, so the player sees the answer. Either outcome disables the entire keyboard and reveals the "Play Again" button, which calls newGame() to pick a fresh random word, reset guessedLetters, hide all gallows parts, and rebuild the keyboard from scratch.

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 explain how PART_ORDER and revealBodyPart() work together to turn a single wrongCount integer into the correct sequence of visible SVG body parts — that indirection is the cleverest part of the implementation and worth understanding fully before you extend it. It's also a strong candidate for AI-assisted improvements: ask the assistant to add word categories or difficulty levels by restructuring the WORDS array, to add a hint system that reveals one free letter after three wrong guesses, or to add a simple win/loss streak counter persisted in localStorage across rounds. You could also ask it to review the shared guessLetter() code path for the on-screen keyboard and the physical keydown listener and confirm there's no way for a disabled key's guess to be double-counted. Use it as a live collaborator to poke at the logic, not just a black box to copy.

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 classic Hangman word-guessing game in plain HTML, CSS, and JavaScript — no frameworks, no build tooling.

Requirements:
- A hidden word chosen randomly from a small hardcoded word list at the start of each game, displayed as a row of underscore placeholders that reveal the correct letter (in every matching position at once) as soon as it is guessed correctly.
- A visual penalty figure (built from layered SVG or stacked CSS shapes, for example a hangman gallows) that reveals exactly one additional piece for each wrong guess, up to a maximum of 7 wrong guesses before the game ends in a loss.
- Both a clickable on-screen QWERTY keyboard and support for real physical keyboard input, routed through the same underlying guess-handling function so behavior never diverges between the two input methods.
- Already-guessed letters must become visually disabled/greyed out on the on-screen keyboard immediately after being guessed, with a distinct visual treatment for correct versus incorrect guesses, and must not be guessable again from either input method.
- A win condition when every letter in the word has been guessed before running out of wrong guesses, and a loss condition when wrong guesses reach the maximum — on loss, reveal the full secret word even if it was not completed.
- A "Play again" control that starts a brand-new round with a new random word, resets the wrong-guess count, hides the penalty figure, and re-enables the full keyboard.
- Handle repeated letters correctly (for example guessing a letter that appears multiple times in the word reveals all of its occurrences in a single guess) and ignore invalid input (non-letter keys, already-guessed letters) without penalising the player.

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
    Guess a letterClick any letter on the on-screen keyboard, or simply type on your physical keyboard — the document-level keydown listener normalises input and calls the same guessLetter() function either way.
  2. 2
    Watch correct guesses reveal instantlyA correct letter reveals every matching position in the word at once via the guessedLetters Set lookup in renderWord(), and the corresponding on-screen key turns green and becomes disabled.
  3. 3
    Track wrong guesses on the gallowsEach wrong guess increments wrongCount, updates the "X / 7 wrong guesses" counter, and calls revealBodyPart() to fade in the next SVG body part — rope, head, body, arm, arm, leg, leg — in that fixed order.
  4. 4
    Reach a win or loss stateGuessing every letter in the word before reaching 7 wrong guesses triggers a win message; reaching 7 wrong guesses first triggers a loss message and forcibly reveals the full word via revealWordFully().
  5. 5
    Start a new roundClick "Play Again" to call newGame(), which picks a new random word from the WORDS array, clears guessedLetters, resets wrongCount to zero, hides all gallows parts, and rebuilds a fully enabled keyboard.
  6. 6
    Expand the word listAdd or replace entries in the WORDS array at the top of the JS panel — keep them uppercase since guessLetter() compares against uppercase input, or add a themed category selector that swaps in a different array before calling newGame().

Real-world uses

Common Use Cases

Vocabulary and spelling practice for classrooms or language apps
Hangman is a long-standing tool for reinforcing spelling and vocabulary recall. Swap the WORDS array for a themed list (science terms, a foreign-language vocabulary set, spelling-bee words) to repurpose this snippet as a quick practice widget inside an educational site or app section.
Casual mini-game for a portfolio, waiting screen, or 404 page
Because the whole game is self-contained with no external state and no dependencies, it works well embedded as a lightweight distraction on a 404 error page, a loading screen, or a personal site's "fun stuff" section, similar in spirit to a Whack-a-Mole Game used for the same purpose.
Reference for building accessible dual-input games
The pattern of routing both click events and keydown events through a single shared handler function is a reusable technique worth studying for any game or form widget that needs to support both mouse/touch and keyboard users without duplicating logic or risking the two input paths drifting out of sync.
Themed reskin for a branded word-game promotion
Replace the SVG stroke colours, the dark background, and the accent colour with brand colours to turn this into a promotional word-guessing activation — for example a product-name guessing game where the hidden words are product features or brand terms relevant to a marketing campaign.
Demonstrating state-machine game design in a code walkthrough
The clean separation between state (secretWord, guessedLetters, wrongCount, gameOver), rendering (renderWord, revealBodyPart), and input handling (guessLetter) makes this a useful teaching example for explaining game state machines to junior developers without the complexity of a canvas-based game loop.
Kids' learning app letter-recognition exercise
The large, clearly labelled on-screen QWERTY keyboard combined with instant visual feedback (green for correct, red for wrong) makes this snippet adaptable as a simple letter-recognition or early-reading exercise for younger users, especially when paired with a WORDS list of short, simple words.

Got questions?

Frequently Asked Questions

A PART_ORDER array lists the CSS class names of the seven hangman parts in the exact sequence they should appear (rope, head, body, both arms, both legs). Each wrong guess calls revealBodyPart(wrongCount - 1), which looks up PART_ORDER at that index and adds a .show class to the matching SVG element, flipping its opacity from 0 to 1 via a CSS transition — no coordinate math or redrawing is involved.

A Set gives constant-time has() lookups, which keeps duplicate-guess checking and word-completion checking fast regardless of word length, and it inherently rejects duplicate values so the same letter can never be counted twice even if guessLetter() were somehow called twice with the same letter.

Yes. A single keydown listener on document normalises e.key to uppercase and, if it is a letter A-Z, calls the exact same guessLetter() function that the on-screen keyboard buttons call. There is no separate code path for physical typing, so behaviour (including duplicate-guess prevention and disabling used keys visually) stays consistent between both input methods.

Seven, defined by the MAX_WRONG constant, which matches the seven SVG parts revealed after the always-visible gallows frame (rope, head, body, two arms, two legs). Change MAX_WRONG to make the game easier or harder — note you would also need to adjust PART_ORDER if you change the total number of visual stages.

Yes — replace the single flat WORDS array with an object of categories, for example { easy: [...], hard: [...] }, add a category selector to the HTML, and update newGame() to pick a random word from the currently selected category array instead of the single WORDS constant. The rest of the game logic (guessing, rendering, win/loss detection) needs no changes.