Introduction
In this project, we will create a drag-and-drop puzzle game using React. This is an excellent project for beginners to learn about React components, state management, and handling user interactions. By the end of this project, you will have a functional puzzle game.
👀 Preview

🎯 Tasks
In this project, you will learn:
- How to set up a new React application
- How to create the main puzzle game component
- How to manage state and set up the puzzle image
- How to display puzzle pieces on the screen
- How to implement drag and drop functionality
- How to incorporate the PuzzleGame component into the main application file
- How to add CSS to style the puzzle
🏆 Achievements
After completing this project, you will be able to:
- Set up a React application and create a component
- Manage state and handle user interactions
- Implement drag and drop functionality
- Incorporate styling to make the puzzle visually appealing
Project Setup
Objective: The foundation of our puzzle-game is a new React application.
Open your terminal.
Navigate to your project directory:
cd puzzle-gameInstall project dependencies:
npm install
Create PuzzleGame Component
Objective: Set up the main puzzle game component.
- Inside the
srcdirectory, create a folder namedcomponents. - Within
components, create a new file namedPuzzleGame.js. - Add the following basic structure to
PuzzleGame.js:
// src/components/PuzzleGame.js
// Importing React and useState for managing component state
import React, { useState, useEffect } from "react";
// Defining the PuzzleGame component
const PuzzleGame = () => {
// This component will handle the game logic and UI
return (
<div className="game-container">
{/* This is where the puzzle will be rendered */}
</div>
);
};
// Exporting the component for use in other files
export default PuzzleGame;
Implement State and Image Setup
Objective: Set up the state to manage puzzle pieces and define the puzzle image.
- In
PuzzleGame.js, importuseStatefrom React. - Define a state variable to keep track of the puzzle pieces' positions.
- Define the URL of the puzzle image (place an image named
corgi.pngin thepublicfolder).
// src/components/PuzzleGame.js
// ...other imports
const PuzzleGame = () => {
// Define the image URL and initial positions of puzzle pieces
const imgUrl = "corgi.png"; // Make sure this image exists in the public folder
const [positions, setPositions] = useState([...Array(16).keys()]);
useEffect(() => {
// Shuffle the positions for the initial puzzle setup
setPositions((prevPositions) => {
const newPos = [...prevPositions];
newPos.sort(() => Math.random() - 0.5);
return newPos;
});
}, []);
// Component's return statement
return (
<div className="game-container">
{/* The UI of the puzzle will be added here in later steps */}
</div>
);
};
// Exporting PuzzleGame component
export default PuzzleGame;
Render Puzzle Pieces
Objective: Display the puzzle pieces on the screen.
- Map over the
positionsstate to render individual puzzle pieces. - Each piece should display a portion of the image.
// src/components/PuzzleGame.js
const PuzzleGame = () => {
// ...previous code
return (
<div className="game-container">
<div className="reference-image">
<img src={imgUrl} alt="Reference Image" />
</div>
<div className="puzzle-container">
{positions.map((pos, index) => {
const x = (pos % 4) * 100;
const y = Math.floor(pos / 4) * 100;
return (
<div
key={index}
className="puzzle-piece"
style={{
backgroundImage: `url('${imgUrl}')`,
backgroundPosition: `-${x}px -${y}px`
}}
/>
);
})}
</div>
</div>
);
};
Add Drag and Drop Functionality
Objective: Implement the logic for dragging and dropping puzzle pieces.
- Add handlers for drag start, drag over, and drop events.
- Implement the logic to swap puzzle pieces when dropped.
// src/components/PuzzleGame.js
const PuzzleGame = () => {
// ...previous code
// Handling the start of a drag event
const handleDragStart = (e, position) => {
e.dataTransfer.setData("text/plain", position);
};
// Handling the drop event
const handleDrop = (e, position) => {
e.preventDefault();
const originalPosition = e.dataTransfer.getData("text");
// Add logic here to swap positions of puzzle pieces
setPositions((prevPositions) => {
const newPos = [...prevPositions];
[newPos[originalPosition], newPos[position]] = [
newPos[position],
newPos[originalPosition]
];
return newPos;
});
};
// Allowing the drop action by preventing default behavior
const handleDragOver = (e) => {
e.preventDefault();
};
// Render puzzle pieces with added drag and drop handlers
};
// src/components/PuzzleGame.js
const PuzzleGame = () => {
// ...previous code
return (
<div className="game-container">
<div className="reference-image">
<img src={imgUrl} alt="Reference Image" />
</div>
<div className="puzzle-container">
{positions.map((pos, index) => {
const x = (pos % 4) * 100;
const y = Math.floor(pos / 4) * 100;
return (
<div
key={index}
className="puzzle-piece"
draggable
onDragStart={(e) => handleDragStart(e, index)}
onDrop={(e) => handleDrop(e, index)}
onDragOver={handleDragOver}
style={{
backgroundImage: `url('${imgUrl}')`,
backgroundPosition: `-${x}px -${y}px`
}}
/>
);
})}
</div>
</div>
);
};
Updating the App Component
Objective: Incorporate the PuzzleGame component into the main application file.
- Open
src/App.js. - Render the PuzzleGame component.
// src/App.js
import React from "react";
import "./App.css";
import PuzzleGame from "./components/PuzzleGame";
// App component that renders the PuzzleGame component
function App() {
return (
<div className="App">
<PuzzleGame />
</div>
);
}
export default App;
Styling the Puzzle
Objective: Add CSS to make the puzzle visually appealing.
- Open
src/App.css. - Add styles for
.game-containerand.puzzle-pieceto layout the puzzle correctly.
body {
font-family: "Arial", sans-serif;
text-align: center;
padding: 20px;
background: #f0f0f0;
}
.game-container {
display: flex;
justify-content: center;
align-items: flex-start;
gap: 20px;
}
.reference-image {
display: flex;
align-items: center;
justify-content: center;
border: 3px solid #aaa9a9;
/* Add a border for consistency */
padding: 10px;
/* Add some padding around the image */
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
/* Add shadow for depth */
}
.reference-image img {
display: block;
/* Remove any default inline spacing */
max-width: 200px;
}
.puzzle-container {
width: 400px;
height: 400px;
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 2px;
border: 5px solid #aaa9a9;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
/* Add a larger shadow for a 3D effect */
background: #ddd;
/* Light background for the gaps */
}
.puzzle-piece {
width: 100%;
height: 100%;
background-size: 400px 400px;
cursor: grab;
box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.3);
/* Add inset shadow for each piece */
}
Running the Application
Objective: Launch the application to see the completed puzzle game.
In your project directory, run:
npm startThe application should open in your web browser, displaying the puzzle game.
Summary
Congratulations! You've successfully built a drag-and-drop puzzle game in React. This project covered setting up a React project, creating components, managing state, handling user interactions, and applying basic styles. You can now experiment with adding more features like a timer, score, or different levels to enhance the game.



