diff --git a/joke-generator/index.html b/joke-generator/index.html
new file mode 100644
index 000000000..c8c3c2966
--- /dev/null
+++ b/joke-generator/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+ Random Joke Generator
+
+
+
+
+
+ 😂 Random Joke Generator
+
+ Click the button to get a joke!
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/joke-generator/script.js b/joke-generator/script.js
new file mode 100644
index 000000000..839a5090f
--- /dev/null
+++ b/joke-generator/script.js
@@ -0,0 +1,37 @@
+// Grab the elements we need from the page
+const jokeText = document.getElementById("joke-text");
+const jokeBtn = document.getElementById("joke-btn");
+
+// URL of the free joke API we're using (no API key required)
+const API_URL = "https://official-joke-api.appspot.com/random_joke";
+
+// Function to fetch a new joke and display it
+async function getJoke() {
+ // Disable the button and show a loading message while we fetch
+ jokeBtn.disabled = true;
+ jokeText.textContent = "Loading...";
+
+ try {
+ const response = await fetch(API_URL);
+
+ // If the request failed, throw an error to be caught below
+ if (!response.ok) {
+ throw new Error("Network response was not ok");
+ }
+
+ const data = await response.json();
+
+ // The API returns { setup: "...", punchline: "..." }
+ jokeText.textContent = `${data.setup} — ${data.punchline}`;
+ } catch (error) {
+ // Show a friendly message if something goes wrong
+ jokeText.textContent = "Oops! Couldn't fetch a joke. Please try again.";
+ console.error("Error fetching joke:", error);
+ } finally {
+ // Re-enable the button no matter what happened
+ jokeBtn.disabled = false;
+ }
+}
+
+// Run getJoke() every time the button is clicked
+jokeBtn.addEventListener("click", getJoke);
\ No newline at end of file
diff --git a/joke-generator/style.css b/joke-generator/style.css
new file mode 100644
index 000000000..6eb8a7ea1
--- /dev/null
+++ b/joke-generator/style.css
@@ -0,0 +1,64 @@
+* {
+ box-sizing: border-box;
+}
+
+body {
+ margin: 0;
+ min-height: 100vh;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: linear-gradient(135deg, #ff9a9e, #fad0c4);
+ font-family: "Segoe UI", Arial, sans-serif;
+}
+
+.card {
+ background: #ffffff;
+ padding: 2.5rem 2rem;
+ border-radius: 16px;
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
+ max-width: 480px;
+ width: 90%;
+ text-align: center;
+}
+
+h1 {
+ margin-top: 0;
+ font-size: 1.6rem;
+ color: #333;
+}
+
+#joke-text {
+ min-height: 80px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 1.1rem;
+ color: #444;
+ margin: 1.5rem 0;
+ padding: 0 0.5rem;
+}
+
+button {
+ background: #ff6b6b;
+ color: white;
+ border: none;
+ padding: 0.8rem 1.6rem;
+ font-size: 1rem;
+ border-radius: 8px;
+ cursor: pointer;
+ transition: background 0.2s ease, transform 0.1s ease;
+}
+
+button:hover {
+ background: #ff4c4c;
+}
+
+button:active {
+ transform: scale(0.97);
+}
+
+button:disabled {
+ background: #ccc;
+ cursor: not-allowed;
+}
\ No newline at end of file