Wordle 45-Minutes Challenge

June 27, 2024

I recently took on a 45-minute Wordle challenge. The goal? Build the popular Wordle game using React in just 45 minutes. ⏱️

For anyone who hasn’t played, Wordle is a word puzzle game. You get six tries to guess a five-letter word. After each guess, you get feedback: green for the right letter in the right spot, yellow for the right letter in the wrong spot, and gray for letters not in the word at all.

Inspiration

This challenge idea came from Conner Ardman and Clément Mihailescu, who did a similar React coding challenge. You can check out their full video here.

Recording

I’m not a pro content creator, so I recorded a sped-up version of my coding process. It’s not the most polished, but I hope it’s interesting.

Getting Started

First, I set up a new project using Next.js instead of React. Next.js is a great starter because it comes with the setup done. To start a new Next.js project, use this command:

yarn create next-app

With my project ready, I started coding and set a timer. Here’s how it went.

Setting Up the Game State

My first step was to set up the game’s state. I used the useState hook to manage:

  • The word to guess
  • The player’s current guess
  • The guesses they made so far

I also used the useEffect hook to pick a random word from a list stored in a JSON file. I found this list on GitHub and converted it to a JavaScript array using arrayThis.

const Wordle = () => {
  const [solution, setSolution] = useState('')
  const [currentGuess, setCurrentGuess] = useState('')
  const [isGameOver, setIsGameOver] = useState(false)
  const [guesses, setGuesses] = useState<(string | null)[]>(
    Array.from({ length: 6 }).fill(null) as (string | null)[]
  )

  const fetchNewSolution = useCallback(() => {
    const wordsLength = WordsList.length
    const randomIndex = Math.floor(Math.random() * wordsLength)
    setSolution(WordsList[randomIndex])
  }, [])

  useEffect(() => {
    fetchNewSolution()
  }, [])
}

export default Wordle

Input Handling

Next, I needed to capture user input. I used the onkeydown event to get each letter as it was typed. This way, I didn’t need to use an input field, keeping it simple.

const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
  if (e.key === 'Enter') return handleGuess()
  if (e.key === 'Backspace')
    return setCurrentGuess((currentGuess) => currentGuess.slice(0, -1))
  return setCurrentGuess((currentGuess) => currentGuess + e.key)
}

Implementing Feedback Logic

Now, I created the feedback logic. This compares the player’s guess to the solution and changes the colors of each letter to show if it’s correct.

const handleGuess = () => {
  const currentGuessLowerCase = currentGuess.toLowerCase()
  const solutionLowerCase = solution.toLowerCase()

  if (currentGuessLowerCase.length !== 5) return

  if (guesses.length === 6) return setIsGameOver(true)

  const isSolution = solutionLowerCase === currentGuessLowerCase

  if (isSolution) {
    setIsGameOver(true)
    return
  }

  setGuesses((guesses) => [
    ...guesses.slice(0, currentGuess.length),
    isSolution ? null : currentGuess,
  ])
}

Rendering the Game

With the main logic done, it was time to create the UI. I made a simple UI to show the player’s guesses and feedback.

return (
  <div className="h-screen w-screen flex flex-col items-center justify-center gap-8">
    <h1 className="text-3xl font-medium">Wordle</h1>
    <div className="flex flex-col items-center gap-y-4">
      {guesses.map((guess, index) => (
        <Guess
          guess={currentGuessIndex === index ? currentGuess : guess ?? ''}
          solution={solution}
          isStillGuessing={currentGuessIndex === index}
          key={index}
        />
      ))}
    </div>
    <AnimatePresence mode="wait">
      {isGameOver && (
        <motion.div
          className="fixed inset-0 z-50 bg-gray-100/50 flex items-center justify-center"
          initial={{ opacity: 0 }}
          animate={{ opacity: 1 }}
          exit={{ opacity: 0 }}
          transition={{ duration: 0.5, ease: 'easeInOut' }}
        >
          <GameOver
            isWinner={guesses[currentGuessIndex - 1] === solution}
            rounds={currentGuessIndex}
            solution={solution}
            onPlayAgain={onPlayAgain}
          />
        </motion.div>
      )}
    </AnimatePresence>
  </div>
)

And the Guess component:

const Guess = ({ isStillGuessing, guess, solution }: GuessesProps) => {
  const arr = Array(5).fill('')

  for (let i = 0; i < guess.length; i++) {
    arr[i] = guess[i]
  }

  return (
    <div className="grid grid-cols-5 gap-x-2">
      {arr.map((char, index) => {
        const isColored = !isStillGuessing && char !== ''
        const isGreen = isColored && solution.charAt(index) === char
        const isYellow = isColored && !isGreen && solution.includes(char)
        const isGray = isColored && !isGreen && !isYellow

        return (
          <div
            className={cn(
              'w-14 h-14 border border-gray-200 rounded flex items-center justify-center text-2xl',
              {
                'bg-green-400': isGreen,
                'bg-yellow-400': isYellow,
                'bg-gray-200': isGray,
              }
            )}
            key={index}
          >
            {char}
          </div>
        )
      })}
    </div>
  )
}

Final Thoughts

Completing a Wordle game in React within 45 minutes was a fun and intense challenge. While there's always room for improvements, like polishing the design, this project was a great way to practice coding under time pressure.

If you enjoy fast-paced coding, challenges like this one are a perfect way to boost your skills and creativity. I’d love to hear your thoughts or see your own versions—feel free to reach out on social media or by email!

Get Updates

Join my newsletter to keep up with my latest projects, articles, and the cool stuff i find online.