Skip to main content

Command Palette

Search for a command to run...

Build a Tiny Meme Generator — a friendly step-by-step guide

By Kaustubhya Shukla (ksd)

Published
•4 min read•View as Markdown
K

Student | Front End Developer | Writing blogs to share my learnings and Learning in Public

Want a small, fun project you can drop on a page and show off? This guide walks you through a minimal meme generator built with plain HTML, CSS, and JavaScript. It’s written in an easy, conversational style so you can easily complete it.

What you’ll end up with

A single-page app that fetches a random wholesome meme from a meme API and displays the image, its title, and the author. There’s a “Generate Meme” button and a simple loading indicator. No frameworks, no build step — just three files.

File structure

Create a new folder and add these three files:

meme-generator/
├─ index.html
├─ style.css
└─ script.js

index.html — the page skeleton

This file contains the HTML structure and links to the stylesheet and script. The script is loaded with defer so it runs after the DOM is ready.

Example structure (keep it simple):

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Meme Generator</title>
    <link rel="stylesheet" href="style.css" />
    <script src="./script.js" defer></script>
  </head>
  <body>
    <h1>Meme generator</h1>
    <main>
      <div class="meme-container">
        <button class="generate-meme">Generate Meme</button>
        <div class="loading">loading...</div>
      </div>
    </main>
  </body>
</html>

Why defer? It lets your script use document.querySelector right away without listening for DOMContentLoaded.


style.css — clean, minimal styling

Keep the CSS minimal so the UI is readable on desktop and mobile. Key ideas:

  • Center the content and give a comfortable max width.

  • Style the button so it looks clickable.

Example highlights:

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: sans-serif;
}

body {
    width: 100%;
    height: 100%;
}

h1 {
    text-align: center;
    margin: 20px 0;
}

main {
    margin-top: 40px;
    display: flex;
    justify-content: center;
}

.loading {
    max-width: 200px;
    min-height: 200px;
    width: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 18px;
    font-weight: 700;
    background-color: rgb(247, 238, 238);
    margin-top: 30px;
}

.meme-container {
    max-width: 500px;
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.generate-meme {
    font-size: 22px;
    color: #108070;
    background-color: #fff;
    font-weight: 700;
    padding: 8px 20px;
    border-top: none;
    border-bottom: none;
    border-left: 4px solid #222; 
    border-right: 4px solid #222; 
    cursor: pointer;
}

.generate-meme:hover {
    letter-spacing: 3px;
    padding: 8px 36px;
    border-left: 8px solid #222; 
    border-right: 8px solid #222; 
    transition: all 0.3s ease-in-out;   
}

.meme-content {
    background-color: rgb(247, 238, 238);
    box-shadow: rgba(0, 0, 0, 0.2) 10px 10px 16px;
    width: 100%;
    margin-top: 30px;
    display: flex;
    flex-direction: column;
    padding: 20px 50px;
    row-gap: 30px;
    flex-wrap: wrap;
}

.meme-text {
    text-align: center;
    font-size: 24px;
    font-weight: 700;
    margin-top: 20px;
}

.meme-image-container {
    width: 100%;
}

.meme-image {
    width: 100%;
}

.meme-author-container {
    display: flex;
    justify-content: center;
    column-gap: 5px;
    font-size: 20px;
}

Tweak colors, spacing, and typography to match your taste.


script.js — fetching memes and updating the DOM

This is the core. The script fetches a meme from https://meme-api.com/gimme/wholesomememes, shows a loading indicator while the request is in progress, then injects a small card with title, image, and author.

A clean, slightly more robust script using async/await:

const memeButton = document.querySelector(".generate-meme");
const memeContainer = document.querySelector(".meme-container");
const loading = document.querySelector(".loading");

const memeContent = document.createElement("div");
memeContent.classList.add("meme-content");

function getMemes() {
  fetch("https://meme-api.com/gimme/wholesomememes")
    .then((res) => {
      if (!res.ok) {
        console.log("Network error: " + res.status);
      }
      return res.json();
    })
    .then((data) => {
    //   console.log(data);
      loading.style.display = "none";
      memeContent.innerHTML = ""; // Clear previous memes

      memeContent.innerHTML = `      
          <p class="meme-text">${data.title}</p>
          <div class="meme-image-container">
            <img
              class="meme-image"
              src="${data.url}"
              alt="meme-image"
            />
          </div>
          <div class="meme-author-container">
            <p>Meme By:</p>
            <p class="meme-author">${data.author}</p>
          </div>`;
      memeContainer.appendChild(memeContent);
    });
}

getMemes();

memeButton.addEventListener("click", () => {
  getMemes();
});

What does this do:

  • Show the loading box initially when your DOM loads

  • When the DOM loads and the fetch function is called, you see the meme name, meme image and meme author

  • Click `generate me` button to keep generating new memes by calling the fetch api again and again.

To run it, go to VS Code, install the LIVE SERVER extension, and when done, reload the site and click on GO LIVE on the bottom of the screen and you’ll see the end result.

Want to see it live → Click Here

Want code for this in github → Click here

And voila!! You have made a meme generator project.

Thanks for reading → Kaustubhya :)