DEV Community

Michael Lip
Michael Lip

Posted on • Originally published at zovo.one

Building a Mad Lib Engine With Template Literals and Part-of-Speech Tagging

Mad Libs seem like a trivial programming exercise. Replace placeholder words in a template with user input. Five minutes, right? Then you try to make it actually good, and you discover that natural language is full of edge cases that turn a toy project into a legitimate text processing challenge.

The basic engine

The simplest Mad Lib implementation uses template strings with placeholders:

function madlib(template, words) {
  return template.replace(/\{(\w+)\}/g, (match, key) => {
    return words[key] || match;
  });
}

const template = "The {adjective} {noun} {verb} over the {adjective2} {noun2}.";
const words = {
  adjective: "purple",
  noun: "elephant",
  verb: "jumped",
  adjective2: "lazy",
  noun2: "fence"
};

madlib(template, words);
// "The purple elephant jumped over the lazy fence."
Enter fullscreen mode Exit fullscreen mode

This works but has problems. You need unique keys for every placeholder, which means the template author has to invent names like adjective2 and adjective3. It does not enforce part-of-speech correctness. And it does not handle articles (a/an) properly.

The a/an problem

English uses "a" before consonant sounds and "an" before vowel sounds. When a user provides a random adjective or noun, the article might be wrong.

"I saw a elephant" → wrong
"I saw an elephant" → correct
"I saw a unique elephant" → correct (u sounds like "yoo")
"I saw an hour later" → correct (h is silent)
Enter fullscreen mode Exit fullscreen mode

The naive approach of checking the first letter fails because English pronunciation does not always match spelling. A more robust check:

function aOrAn(word) {
  const vowelSound = /^[aeiou]/i;
  const uExceptions = /^uni|^use|^uti|^usu/i;
  const silentH = /^hour|^honest|^honor|^heir/i;

  if (silentH.test(word)) return 'an';
  if (uExceptions.test(word)) return 'a';
  if (vowelSound.test(word)) return 'an';
  return 'a';
}
Enter fullscreen mode Exit fullscreen mode

This covers the common cases but is still imperfect. English pronunciation exceptions are extensive. For a production-quality Mad Lib engine, you would need a pronunciation dictionary.

Part-of-speech categories

Good Mad Libs need grammatically correct prompts. The classic categories:

  • Noun - person, place, thing (dog, Paris, happiness)
  • Verb - action (run, think, calculate)
  • Adjective - describes a noun (red, enormous, fragile)
  • Adverb - describes a verb (quickly, reluctantly, never)
  • Plural noun - more than one (dogs, cities, ideas)
  • Past tense verb - already happened (ran, thought, calculated)
  • Proper noun - specific name (Michael, Japan, Tuesday)
  • Exclamation - outburst (wow, oops, yikes)

The key insight for Mad Libs is that verb tense must match the template. If the template says "Yesterday, I {past_tense_verb} to the store," prompting for a generic "verb" will produce "Yesterday, I run to the store." Tense-specific prompts produce better results.

Template design principles

After building several Mad Lib systems, I have found these principles produce the funniest results:

Juxtapose the mundane with the absurd. Templates about everyday activities produce better laughs than templates about already-silly situations. "I went to the {adjective} grocery store and bought 47 {plural_noun}" works better than "The alien from {noun} planet did something {adjective}."

Use specific quantities. "I ate {number} {plural_noun} for breakfast" is funnier than "I ate some {plural_noun}" because the specificity creates a more vivid mental image.

Include emotional reactions. Adding "{exclamation}!" after a key reveal gives the generated story rhythm and comedic timing.

Keep templates short. Three to five sentences is the sweet spot. Longer templates dilute the humor because there are too many random words competing for attention.

Generating word lists

If you want to provide suggestions or auto-fill options, you need categorized word lists. Here is a minimal structure:

const wordLists = {
  noun: ['bicycle', 'telescope', 'sandwich', 'volcano', 'penguin'],
  adjective: ['enormous', 'invisible', 'grumpy', 'sparkly', 'ancient'],
  verb: ['exploded', 'whispered', 'calculated', 'somersaulted', 'evaporated'],
  adverb: ['frantically', 'suspiciously', 'elegantly', 'accidentally'],
  plural_noun: ['dinosaurs', 'spreadsheets', 'tacos', 'submarines'],
  exclamation: ['Yikes', 'Holy cow', 'Good grief', 'Woah']
};
Enter fullscreen mode Exit fullscreen mode

The best word lists have a mix of mundane and unexpected words. "Bicycle" is funnier in a Mad Lib than "thing" because it is specific enough to create a mental image.

Using it for creative writing warm-ups

Beyond the humor, Mad Libs are a legitimate creative writing tool. They force unexpected word combinations that can spark ideas. Professional writers and game designers use randomized prompts to break out of creative ruts. A Mad Lib that generates "The invisible accountant somersaulted suspiciously toward the volcano" is absurd, but it might seed a story idea.

For generating Mad Libs quickly, whether for entertainment, classroom use, or creative warm-ups, I built a generator at zovo.one/free-tools/madlib-generator. It includes template selection, part-of-speech prompts, and proper article handling. The technical challenge is modest, but the results are reliably entertaining.


I'm Michael Lip. I build free developer tools at zovo.one. 500+ tools, all private, all free.

Top comments (0)