-
Notifications
You must be signed in to change notification settings - Fork 3
Creating Winter Mad Libs
Mad Libs are stories with words removed and replaced by blank spaces. Each player fills in the blanks for a fun story! Make sure to think outside the box. The wackier, the better!
Before starting, you'll need to find a story to use for your Mad Libs. A simple Google search should lead you to tons of stories of different genres, or you can get creative and make your own!
This Wiki will walk you through the process of creating your own version of Winter Mad Libs.
➡️ Full YouTube Video Tutorial by Bree Hall
Table of Contents
3. Create Form Submit and Story Generation Functionality
4. Making This Tutorial Project Your Own
1. This first thing we want to do is create the required files for our project and connect them. This project will only require vanilla HTML, CSS, and JavaScript, so we won't be adding in additional libraries or frameworks. In your desired directory, create the following files:
MadLibs.html
for the structure
MadLibs.css
for the styling
MadLibs.js
for added functionality
2. Configure the HTML Document
After the files have been created, open MadLibs.html
. Create a basic HTML5 page by creating or copying the HTML5 boiler plate code.
Hint: If you're using Visual Studio code, you can type html:5
to render the boiler plate code for you. Not using Visual Studio Code? You can copy the HTML5 boiler plate code here.
After loading in the HTML5 boiler plate, update the <title>
to reflect the name of the project (or whatever you see fit). Then, connect the other two files that will help us build Mad Libs (MadLibs.css
and MadLibs.js
).
In order to connect MadLibs.css
, add a <link>
to the <head>
in MadLibs.html
where rel="stylesheet"
and href
is equal to the local address of the MadLibs.css
file.
To connect the MadLibs.js
, add a <script>
to the bottom of the <body>
where the src
is equal to the local address of the MadLibs.js
file.
Hint: I always like to create some simple logic in my CSS and JavaScript files when I link them to my HTML just to make sure they're connected properly. If you would like to do the same, try this:
In MadLibs.css
, add a rule to make the backgroud-color
of the body
blue. Use: body { background-color: blue; }
.
In MadLibs.js
, add an alert statement with a simple message like Hello. Use alert("Hello!");
.
Open your MadLibs.html
file in your favorite browser and you should notice that the background color of the document is blue and there should be an alert with the message you entered. If you notice one of these two things didn't happen, you may need to review the location you provided to the <link>
or the <script>
. Just make sure to remove these statements after you've validated the connections.
⭐ Checkpoint
At this current point, the MadLibs.html
should look something like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./madlibs.css">
<title>Mad Libs</title>
</head>
<body>
<!-- JS Script inclusion -->
<script src="./madlibs.js"></script>
</body>
</html>
3. Create the Document <header>
Now that the structure of the project has been created and all required files have been connected, let's create the <header>
for our page. The header will tell users what our app is, give a description about the game, and tell users how to play the game. Feel free to get creative with this!
In the <body>
, create a <header>
. Inside of the <header>
create the following:
-
An
<h1>
with the title of our project -
An
<h2>
with the subtitle of our project. For this, I will be using the name of the story the users will be creating. -
A
<p>
with an explanation of the game
Here's what your <header>
should look like:
<header>
<h1 >Winter Mad Libs</h1>
<h2>❄️Fun Facts About Winter ☃️</h2>
<p><strong>Mad Libs</strong> are stories with words removed and replaced by blank spaces. Fill in the blanks for a fun winter story! Make sure to think outside the box. The wackier the better!</p>
</header>
At this point, we have a very bare bones app! If you open MadLibs.html
in your browser, you won't see a lot, but you will be able to see the content from the <header>
we just created. Here's an example of what you should see:
4. Add Styling to the Header and Home Page
The styling for this app is completely optional as you may want to style your app a different way. The styling that I create in this tutorial is just what I think looks nice. Get as creative as you would like! Open MadLibs.css
to get started.
- Add a Background: The first thing I'm going to tackle is the background. Let's add a rule that targets the
body
to add a nice blue gradient.
body{
background-color: #63a4ff;
background-image: linear-gradient(315deg, #63a4ff 0%, #83eaf1 74%);
}
Now, when you take a look at this change in your browser, you may notice that the gradient is repeated for the height of our header section. That's not exactly what we want. It should span the height of the entire document, so add a rule to target the html
and give it a height
of 100%.
html{
height: 100%;
}
Hint: Gradients can be very tricky to work with, so don't feel like you always have to create them on your own. There are lots of designers and developers who have submitted their work to make our lives a little easier. The gradient being used here can be found here on EggGradients.com.
- Update the Document Font: Let's change the basic Times New Roman font within our app. Google has a whole repo of free fonts that can be added to your projects. They're free and easy to use. For this app, I'll be using
Poppins
, but visit fonts.google.com to check out all of the fonts that are available.
Once the font has been selected on Google Fonts, they provide us with a <link>
to use in the <head>
of our HTML that will link the font so we can use it. We're going to copy all three links provided by Google and add them to our MadLibs.html
in the <head>
between the existing metadata and the link to MadLibs.css
.
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap" rel="stylesheet">
After the links have been added to MadLibs.html
, we will be able to use them in our CSS. In MadLibs.css
, let's add a style to the existing body{}
rule to set the font-family
of our body to Poppins.
font-family: 'Poppins', sans-serif;
⭐ Checkpoint
At this point, your MadLibs.html
should look like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="./madlibs.css">
<title>Mad Libs</title>
</head>
<body>
<header>
<h1 >Winter Mad Libs</h1>
<h2>❄️Fun Facts About Winter ☃️</h2>
<p><strong>Mad Libs</strong> are stories with words removed and replaced by blank spaces. Fill in the blanks for a fun winter story! Make sure to think outside the box. The wackier the better!</p>
</header>
<!-- JS Script inclusion -->
<script src="./madlibs.js"></script>
</body>
</html>
At this point, your MadLibs.css
should look like this:
html{
height: 100%;
}
body{
background: rgb(131,234,241);
background: linear-gradient(135deg, rgba(131,234,241,1) 9%, rgba(99,164,255,1) 99%);
font-family: 'Poppins', sans-serif;
}
- Create a Glassy Background for the Game Board: In order to make the game board stand out from the background, let's add some styling to play area. This will require us to make a slight adjustment to our structure. Let's create a container
<div>
that will hold our<header>
and soon our<main>
. Give it theclass="container"
so we can apply styles to it.
Note: Be sure to add this the new elements above the JavaScript inclusion tag.
<div class="container">
<header>
<h1 >Winter Mad Libs</h1>
<h2>❄️Fun Facts About Winter ☃️</h2>
<p><strong>Mad Libs</strong> are stories with words removed and replaced by blank spaces. Fill in the blanks for a fun winter story! Make sure to think outside the box. The wackier the better!</p>
</header>
</div>
Over in MadLibs.css
, we're going to create a new rule to target the container
class and give it a white background with 60% opacity. This is going to create the glassy effect for us.
.container{
background-color: rgba(255,255,255,.6 );
}
This looks nice, but we can make it look better by adding a border-radius and shadows. Let's give the container a border-radius
of 20px
and padding
.
.container{
background-color: rgba(255,255,255,.6 );
padding: 30px 0;
border-radius: 20px;
}
Let's give the container some dimension by adding a shadow. Similar to the gradients from above, you don't have to be an expert at shadows to use them. I found lots of great shadows on getcssscan.com. Once I found one I liked, I just had to plug in the code! Let's update the .container
rule with a shadow.
.container{
background-color: rgba(255,255,255,.6 );
padding: 30px 0;
border-radius: 20px;
box-shadow: rgba(50, 50, 93, 0.25) 0px 13px 27px -5px, rgba(0, 0, 0, 0.3) 0px 8px 16px -8px;
}
Things look ok now, but it's taking up a good majority of the width of the page. Let's provide some height and width restrictions so we can still see the nice gradient in the background.
.container{
background-color: rgba(255,255,255,.6 );
padding: 30px 0;
border-radius: 20px;
box-shadow: rgba(50, 50, 93, 0.25) 0px 13px 27px -5px, rgba(0, 0, 0, 0.3) 0px 8px 16px -8px;
min-width: 60vw;
max-width: 70vw;
min-height: 60vh;
max-height: 90vh;
margin: 0 auto;
}
The last styling adjustment we’ll make for now is adding a style to center the container in the middle of the screen so it doesn’t just stay at the top. There are lots of ways to do this, but I’m going to do it by adding flex to the parent of .container
(which is the <body>
) and telling it to align-items: center;
. This will vertically align any child elements of body.
We need to add a rule for height here because the flex will vertically center the child items based on the height of it’s content, but we want it to be the whole page, so we increase the height of the container to be the height of the entire page. But then, we get a scroll bar on the side. This is because we have two elements with heights set to 100%. I wouldn’t use this in all cases because it can get messy, but since we know we only care about the card in the middle, we’re going to set the overflow of y to hidden as well.
Let's update the body{}
rule:
body{
background: rgb(131,234,241);
background: linear-gradient(135deg, rgba(131,234,241,1) 9%, rgba(99,164,255,1) 99%);
font-family: 'Poppins', sans-serif;
height: 100%
display: flex;
align-items: center;
overflow-y: hidden;
}
⭐ Checkpoint
So far, we've completed the following:
✅ Created the structure for our Mad Libs projects
✅ Created our document <header>
✅ Created the initial styling for the project
At this point, your MadLibs.html
should look like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="./madlibs.css">
<title>Mad Libs</title>
</head>
<body>
<div class="container">
<header>
<h1 >Winter Mad Libs</h1>
<h2>❄️Fun Facts About Winter ☃️</h2>
<p><strong>Mad Libs</strong> are stories with words removed and replaced by blank spaces. Fill in the blanks for a fun winter story! Make sure to think outside the box. The wackier the better!</p>
</header>
</div>
<!-- JS Script inclusion -->
<script src="./madlibs.js"></script>
</body>
</html>
At this point, your MadLibs.css
should look like this:
html{
height: 100%;
}
body{
height: 100%;
overflow-y: hidden;
background: rgb(131,234,241);
background: linear-gradient(135deg, rgba(131,234,241,1) 9%, rgba(99,164,255,1) 99%);
font-family: 'Poppins', sans-serif;
display: flex;
align-items: center;
}
.container{
margin: 0 auto;
min-width: 60vw;
max-width: 70vw;
min-height: 60vh;
max-height: 90vh;
padding: 30px 0;
background-color: rgba(255,255,255,.6 );
border-radius: 20px;
box-shadow: rgba(50, 50, 93, 0.25) 0px 13px 27px -5px, rgba(0, 0, 0, 0.3) 0px 8px 16px -8px;
overflow-y: auto;
}
Here's what our project looks like so far:
With the basic structure and styling of our app set, it's time to create the actual form that users will interact with to create and submit their Mad Libs.
In order to create our form, we'll be using a basic HTML <form>
to compose our play area. The form inputs will be based on the amount of works that should be filled in to complete the story. The story we'll be using for this tutorial has 12 blanks the user must fill in, this means our form should have 12 inputs. If you're interested, you can find a like to the story we'll be using here (Fun Facts About Winter).
1. Create the structure of the play area
Let's create the area of the board where users will input their terms for Mad Libs. We always want to use semantic HTML, so in MadLibs.html
, below the <header>
, add a <main>
containing a <form>
. Be sure to give the <form>
a name
and id
.
<main>
<form id=”madlibs-form” name=”madlibs-form”></form>
</main>
take a second and think about the structure of our form. In the demo, after we input our text, and submit the form to generate the story, the input text goes away and the text on the Generate Button changes to Play Again. One little piece of set up we can do now to help us with that later is to break our form into two
elements. The first section will hold our inputs, and the other section will hold our submit button.<main>
<form id=”madlibs-form” name=”madlibs-form”>
<section id="madlibs-inputs"></section>
<section id="madlibs-submit"></section>
</form>
</main>
2. Create Mad Libs Form Elements
Since Mad Libs is a word game, all of our <input>
elements will have the type
of text
. Something that will be helpful for this step is having a list of inputs your specific story will need right next to you in a list as you develop. Most stories will have multiple inputs that require the same parts of speech, so we have to be good and consistent with our naming conventions.
This two step process will need to be repeated for each term the user will have to submit. First, give each <input>
a <label>
. The label will be paired with an <input>
and tell the browser which input the user is filling out. The for
attribute maps the <label>
to the <input>
, so the text used on this attribute should match the id
attribute of the <input>
.
Label Example
<label for="number">number</label>
Input Example
<input type="text" id="number" name="number" required>
We will be styling the <input>
elements in a later step, so combine these two elements in a <div>
with the class input-group
.
<div class="input-group">
<label for="number">number</label>
<input type="text" id="number" name="number" required>
</div>
Notice that we've also included the required
attribute on the <input>
. This is because we don't want anyone to be able to submit this form without completing all of the fields because they won't have a full story. By adding the required
attribute, we're telling the submit button for the form to double check and make sure all fields are fill out. If not, the user has to go back and review parts they may have missed. Now, complete this process for all of your inputs.
Note:
You may notice I’ve added some emojis to go with my labels. You don’t have to by any means, I just think they’re cute. But if you’re interested, I just got them from emojipedia.com where they allow you to copy and paste emojis.
Now that we have our inputs, all we need is a button to submit our form. Since we're "generating" a story for our users, let's call this button generate. This will be added in the <section>
below the madlibs-inputs
section we created earlier. This button is being used inside of a <form>
, so be sure to set the type
attribute to submit
.
<section id="madlibs-submit">
<button type="submit">Generate</button>
</section>
When completed, your MadLibs.html
should look like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="./madlibs.css">
<title>Mad Libs</title>
</head>
<body>
<div class="container">
<header id="intro" class="center">
<h1 >Winter Mad Libs</h1>
<h2>❄️Fun Facts About Winter ☃️</h2>
<p><strong>Mad Libs</strong> are stories with words removed and replaced by blank spaces. Fill in the blanks for a fun winter story! Make sure to think outside the box. The wackier the better!</p>
</header>
<main>
<!-- Main MadLibs Form Input Area -->
<form id="madlibs-form" name="madlibs-form" onsubmit="submitMadLibs(event)">
<section id="madlibs-inputs">
<div class="input-group">
<label for="number">🔢 number</label>
<input type="text" id="number" name="number" required>
</div>
<div class="input-group">
<label for="adjective_1">🦄 adjective</label>
<input type="text" id="adjective_1" name="adjective_1" required>
</div>
<div class="input-group">
<label for="noun_1">✏️ noun</label>
<input type="text" id="noun_1" name="noun_1" required>
</div>
<div class="input-group">
<label for="noun_2">✏️ noun</label>
<input type="text" id="noun_2" name="noun_2" required>
</div>
<div class="input-group">
<label for="noun_3">✏️ noun</label>
<input type="text" id="noun_3" name="noun_3" required>
</div>
<div class="input-group">
<label for="adjective_2">🦄 adjective</label>
<input type="text" id="adjective_2" name="adjective_2" required>
</div>
<div class="input-group">
<label for="noun_4">✏️ noun</label>
<input type="text" id="noun_4" name="noun_4" required>
</div>
<div class="input-group">
<label for="sport_1">🏀 sport</label>
<input type="text" id="sport_1" name="sport_1" required>
</div>
<div class="input-group">
<label for="sport_2">🏀 sport</label>
<input type="text" id="sport_2" name="sport_2" required>
</div>
<div class="input-group">
<label for="sport_3">🏀 sport</label>
<input type="text" id="sport_3" name="sport_3" required>
</div>
<div class="input-group">
<label for="beverage">🧃 beverage</label>
<input type="text" id="beverage" name="beverage" required>
</div>
<div class="input-group">
<label for="food">🍕 food</label>
<input type="text" id="food" name="food" required>
</div>
</section>
<section id="madlibs-submit">
<button type="submit">Generate</button>
</section>
</form>
</main>
</div>
<!-- JS Script inclusion -->
<script src="./madlibs.js"></script>
</body>
</html>
If you hop over to the browser to check on your work, you should see something similar to this:
3. Styling the Mad Libs Form Inputs
At this point, we have 99% of the inputs we'll be using to generate our Mad Libs! However, as you saw from the last progression photo, our form doesn't look great. The labels and elements are appearing side by side and it would be easier to read if they were stacked. Let's open MadLibs.css
and give this form a facelift.
- Add padding to form sections: Let's start by adding
padding
tosection
elements within the<form>
. We will also tell the section that its contents should use flex to display the<label>
/<input>
pairs in rows.
form section {
padding: 0 5%;
margin-top: 20px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
}
There are lots of ways to achieve a stacked look for the <label>
and <input>
, but this time let's apply flex properties. This will allow us to stack input groups, allow them to flow from left to right, and wrap when there's no room left. In the game of Mad Libs, the users concept for the order of words doesn't matter too much.
- Stack
<label>
and<input>
elements: Let's target the<div>
elements we encased theand
` elements in, apply flex, and add a margin.
.input-group {
display: flex;
flex-direction: column;
margin: 10px;
}
This looks better already, but let's add some custom styling to the <label>
and <input>
elements. I like to pill shaped inputs, so let's give the <input>
elements that treatment by making them taller, wider, and adjusting the border-radius
. A thicker border and box shadow add dimension as well.
.input-group label{
padding-left: 10px;
}
.input-group input[type="text"] {
height: 30px;
width: 250px;
border: 1px solid #edede8;
border-radius: 20px;
box-shadow: rgba(99, 99, 99, 0.1) 0px 2px 2px 0px;
padding-left: 10px;
margin: 3px 0 10px;
}
After these quick styling changes, you MadLibs.css
should look like this:
html{
height: 100%;
}
body{
height: 100%;
overflow-y: hidden;
background: rgb(131,234,241);
background: linear-gradient(135deg, rgba(131,234,241,1) 9%, rgba(99,164,255,1) 99%);
font-family: 'Poppins', sans-serif;
display: flex;
align-items: center;
}
.container{
margin: 0 auto;
min-width: 60vw;
max-width: 70vw;
min-height: 60vh;
max-height: 90vh;
padding: 30px 0;
background-color: rgba(255,255,255,.6 );
border-radius: 20px;
box-shadow: rgba(50, 50, 93, 0.25) 0px 13px 27px -5px, rgba(0, 0, 0, 0.3) 0px 8px 16px -8px;
overflow-y: auto;
}
form section{
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
padding: 0 5%;
margin-top: 20px;
}
.input-group {
display: flex;
flex-direction: column;
margin: 10px;
}
.input-group label{
padding-left: 10px;
}
.input-group input[type="text"] {
height: 30px;
width: 250px;
border: 1px solid #edede8;
border-radius: 20px;
box-shadow: rgba(99, 99, 99, 0.1) 0px 2px 2px 0px;
padding-left: 10px;
margin: 3px 0 10px;
}
If you hop over to the browser to check on your work, you should see something similar to this:
4. Connect Submit Button to Form
We’re going to step away from styling just for a second to connect our submit button to our form and connect our form to our JavaScript.
Currently, if you select the Generate button (with inputs), it appears as though the page has refreshed, but when you take a look at the URL, it’s been updated to include our form inputs. This isn’t exactly what we want, so let’s tell our app what we do want.
In MadLibs.html
, let’s start by providing our <form>
element with the onsubmit
attribute. This is a space where we can pass in a function and tell our form exactly what to do when the submit button is clicked. Let’s give it a function that we’re going to wire up in our JavaScript file next.
<form id="madlibs-form" name="madlibs-form" onsubmit="submitMadLibs(event)">
Now, let's go over to MadLibs.js
and create a simple function to ensure that it is connected to the submit properly.
const submitMadLibs = (event) => {
alert('hey!');
}
Now, when we fill out the form and generate, we get our "hey" message. However, the page still refreshes. What we can do to prevent the page from refreshing by adding one line.
const submitMadLibs = (event) => {
alert('hey!');
event.preventDefault();
}
Now, when we fill out our form and generate, we get our "hey" message and the page doesn’t refresh!
⭐ Checkpoint
So far, we've completed the following:
✅ Created the Mad Libs playing board <form>
with inputs
✅ Styled the Mad Libs form
✅ Wired up the Mad Libs form to our JavaScript with a simple submit function
Now that our form is completely set up and connected to our JavaScript, it's time to create functionality that allows our app to accept and process user inputs. In order to do this, there are two main things we need to do:
- Extract the user input (the players answers)
- Combine the input with the shell of the Mad Libs story to create a full story
1. Retrieving Form Data
The first goal we need to accomplish is retrieving the Mad Libs form data to get our users inputs. Start by creating an object to store our form data. If you look at how we've set up our HTML, we've created inputs that will be perfect for creating key/value pairs we need to fill in the blanks of our story. We're going to utilize FormData
which is a built in API that allows us to easily construct these key/value pairs from our form input.
Let's create a new FormData
object and direct it to our form. In this case, the submitMadLibs
function will only be triggered on submit, so we can be guarenteed that the event target (passed into submitMadLibs
) will always lead to our form. We also want the key/value pairs from our form, so we’re going to use Object.fromEntries
to create an object for us with all of the form data.
const form = new FormData(event.target);
const userSubmission = Object.fromEntries(form);
Let's add a console log to view our userSubmission
object and view it in the browser to take a look at our data.
console.log(userSubmission);
Once in the browser, open the Developer Tools and navigate to the console. Then, fill out the inputs within the Mad Libs form and submit. When you take a look at the console, what you should find is an object with unique keys. It should look similar to this:
adjective_1: "2"
adjective_2: "6"
beverage: "11"
food: "12"
noun_1: "3"
noun_2: "4"
noun_3: "5"
noun_4: "7"
number: "1"
sport_1: "8"
sport_2: "9"
sport_3: "10"
Note: This is a perfect time to double check (or even triple check) to make sure you have all of the inputs that your story will require and that there are no duplicates with input naming.
This gives us a simple object with all of our user form data! This can be accomplished in a number of ways, but I've chosen this way in particular because it makes the next step a little easier.
2. Generating the Story
When it comes to generating the story, it's as simple as using the object we created to fill in the blanks of the story. If styling isn't something important, you can easily use a template string to wire up the inputs and the story shell.
Since we've styled the remainder of the project, I'm going to keep on the same path. In order to do this, we're going to be composing HTML that will be inserted into the project with JavaScript. I'm doing this for two reasons:
- We're going to add styling to the words that the user has inserted (that way they can see the parts they contributed).
- By encasing the story block in a variable, I'm setting myself up for logic that I want to implement later that will remove our text inputs to show the story. Then, when the user wants to play again, we can use the same variable to remove the story and show the inputs again to reset.
An easy way to start this process is by working in a basic text editor or using some empty space in MadLibs.html
. Type our or copy and paste your Mad Libs shell with the blanks.
- Add a
<p>
to the beginning of the story and a</p>
to the end of the story to encase the entire story in a paragraph. - In spots where there are blanks for user input, add a
<span>
withclass="inserted-text"
. This is going to allow us to style those inserted words later.
<span class="inserted-text"> </span>
- Use the output generated from the
userSubmission
object in the console to fill in the blanks. The trick here is we're using a template string. This allows us to plop our object key/value pairs right into the story test. Being able to access the object directly makes this super easy. In order to use the object, you must surround the object like this:${}
. Let's take a look at an example:
If one of the keys in the userSubmission
object is adjective_1
, I would access the value with a <span>
like this:
<span class="inserted-text">${userSubmission.adjective_1}</span>
This should be completed before every blank in the Mad Libs shell. Once the blanks have been filled in, add an <h3>
to the top of your story (above the <p>
).
<h3> Your completed story: </h3>
Your story should look something like this:
<h3>Your completed story:</h3>
<p>Winter is one of <span class="inserted-text">${userSubmission.number}</span> seasons of the year.
The other seasons are <span class="inserted-text">${userSubmission.adjective_1}</span>, <span class="inserted-text">${userSubmission.noun_1}</span>, and
<span class="inserted-text"> ${userSubmission.noun_2}</span>.
Winter is the time of year with the <span class="inserted-text">${userSubmission.noun_3}</span>
is the furthest from the Earth. The weather tends to be <span class="inserted-text">${userSubmission.adjective_2}</span> degrees in the winter, with
<span class="inserted-text">${userSubmission.noun_4} </span>
fall and cold temperatures. Some winter sports include <span class="inserted-text">${userSubmission.sport_1}</span>,
<span class="inserted-text">${userSubmission.sport_2}</span>, and <span class="inserted-text">${userSubmission.sport_3}</span>.
Hot <span class="inserted-text">${userSubmission.beverage}</span>
with <span class="inserted-text">${userSubmission.food}</span> on top is a popular winter drink.</p>
It may look a little jumbled, but that's ok! We're now ready to use it in MadLibs.js
. In the submitMadLibs
function, under userSubmission
, create a new variable for our story. It is important here to use backticks (the character left of the 1 on they keyboard). You won't be able to use single or double quotes. After you've created your variable, copy and paste the new heading and story with inserts into the variable.
const story = `
<h3>Your completed story:</h3>
<p>Winter is one of <span class="inserted-text">${userSubmission.number}</span> seasons of the year.
The other seasons are <span class="inserted-text">${userSubmission.adjective_1}</span>, <span class="inserted-text">${userSubmission.noun_1}</span>, and
<span class="inserted-text"> ${userSubmission.noun_2}</span>.
Winter is the time of year with the <span class="inserted-text">${userSubmission.noun_3}</span>
is the furthest from the Earth. The weather tends to be <span class="inserted-text">${userSubmission.adjective_2}</span> degrees in the winter, with
<span class="inserted-text">${userSubmission.noun_4} </span>
fall and cold temperatures. Some winter sports include <span class="inserted-text">${userSubmission.sport_1}</span>,
<span class="inserted-text">${userSubmission.sport_2}</span>, and <span class="inserted-text">${userSubmission.sport_3}</span>.
Hot <span class="inserted-text">${userSubmission.beverage}</span>
with <span class="inserted-text">${userSubmission.food}</span> on top is a popular winter drink.</p>
`;
Then, add a console log to view the story in the browser's Developer Tools. What you should find is our HTML story, but the inserts from the userSubmission
object should be replaced with the words you used to test.
🎉 Take a quick moment to celebrate! You have successfully created Mad Libs! It needs a little bit of shaping, but we're most of the way there!
A Few Considerations:
- If you're seeing blanks where your user input should be, check to ensure that you're object has the key that you're searching for. It can be easy to duplicate keys or accidently misspell them.
- If you're concerned about new lines and spacing, it's important to note here that a template string does not omit spaces or new lines. You can either represent your story in your code as one long string (which will be broken up and wrapped in the browser), or create new lines where you see fit based on your story.
4. Hide the Main Play Area and Show the Story
Next, in order to allow users to the see the story they created, let's hide the Mad Libs play area and show our story. We can do this by updating our MadLibs.html
slightly and adding a class to MadLibs.css
.
Open MadLibs.html
and head to the bottom of the <form>
. Between the ending of the <form>
and end of the <main>
, let's add a section for our completed story. We want to give it an id that we can target from MadLibs.js
, and we want to give it class="hide
which we will define in the next step.
<section id="completed-story" class="hide"></section>
Open MadLibs.css
and add target the .hide
class. We're going to give this class a display
of none
.
.hide {
display: none;
}
Once you save, you shouldn't see any visual changes. However, if you inspect in the browser's Developer Tools, you should be able to see that the section is there within the HTML.
Let's travel back over to MadLibs.js
and work on our logic to toggle the Mad Libs play area and story section. Before we can start, we need to knew where exactly our story section is in our HTML. We can do this by targeting the id that we just created for the new section we added for the completed story. At the top of the file, use document.getElementById('completed-story')
to retrieve our story container.
const storySection = document.getElementById('completed-story');
We have our story section, and it currently has no contents and it's hidden. Let's move down to the bottom of the submitMadLibs
function to fix that.
When we created our story, we set ourselves up for this step very well. Our story is in the form of HTML, so we can just inject that into the completed-story
section by targeting the innerHTML
of the section and adding onto it.
storySection.innerHTML += story;
What did this do? We've added our generated story HTML to the empty section. At this time, there shouldn't be any visual changes because the completed-story
section still has the hide
class attached to it. We can remove that by targeting the classList
on the element and removing the hide
class.
storySection.classList.remove('hide');
Now, let's head over to the browser and see what we have so far. When we fill out the form and press submit, we have a new area that shows at the bottom! Here you should see your story and inputs (no HTML elements). If you are seeing HTML, try going back and making sure that you have an opening and closing tag for each element.
You should see something like this:
Your MadLibs.js
should look like this:
const storySection = document.getElementById('completed-story');
const submitMadLibs = (event) => {
//required to prevent the form from reloading on submit
event.preventDefault();
madLibsForm.classList.add('hide');
const form = new FormData(event.target);
const userSubmission = Object.fromEntries(form);
const story = `
<h3>Your completed story:</h3>
<p>Winter is one of <span class="inserted-text">${userSubmission.number}</span> seasons of the year.
The other seasons are <span class="inserted-text">${userSubmission.adjective_1}</span>, <span class="inserted-text">${userSubmission.noun_1}</span>, and
<span class="inserted-text"> ${userSubmission.noun_2}</span>.
Winter is the time of year with the <span class="inserted-text">${userSubmission.noun_3}</span>
is the furthest from the Earth. The weather tends to be <span class="inserted-text">${userSubmission.adjective_2}</span> degrees in the winter, with
<span class="inserted-text">${userSubmission.noun_4} </span>
fall and cold temperatures. Some winter sports include <span class="inserted-text">${userSubmission.sport_1}</span>,
<span class="inserted-text">${userSubmission.sport_2}</span>, and <span class="inserted-text">${userSubmission.sport_3}</span>.
Hot <span class="inserted-text">${userSubmission.beverage}</span>
with <span class="inserted-text">${userSubmission.food}</span> on top is a popular winter drink.</p>
`;
storySection.innerHTML += story;
storySection.classList.remove('hide');
}
This is progress, but it's not exactly what we're looking for. When we're viewing the story, we don't want to view the input area. So, we need to use the hide
class on the Mad Libs form just like we used on the completed-story
section. We can basically follow the same steps.
At the top of MadLibs.js
, we need to target the Mad Libs form. We can do this by targeting the ID on the form.
const madLibsForm = document.getElementById('madlibs-form');
Now, inside of the submitMadLibs
function, instead of removing a class from the class list, we want to add one. I'm going to add this above our logic to generate the Mad Libs story. That way, the screen doesn't bounce when adding the completed story to the bottom of the page before removing the form. Under the event.preventDefault()
call, add:
madLibsForm.classList.add('hide');
Head back over to the browser and test once more. This time you should see the toggle! At this point, you have fully created an entire Mad Libs app! You have accepted and processed user input, and generated a fun story! All that we have left is a little styling and the ability for users to reset the form and play again.
5. Style the Completed Story & Story Inputs
I'm going to give the completed story some padding, margin, increase the font-size, and center the text as well. Let's do this by targeting the completed-story
section.
#completed-story{
padding: 0 5%;
margin-top: 15px;
text-align: center;
font-size: 1.5em;
line-height: 2;
}
We want the users to be able to easily see the words they input into the story, so let's give them some style. I'm going to give them a bottom border, make the text bold, change the background color, and provide some padding and margin as well.
.inserted-text{
border-bottom: 3px solid #63A4FF;
font-weight: 700;
background-color: white;
padding: 0 5px;
margin: 0 5px;
6. Toggle Generate and Reset Buttons
What happens when a user has completed the story, but they want to play again? They could refresh to reset, but let's make things easier for them. We currently toggle between the Mad Libs input area and the completed story, and we can do the same thing with buttons! Instead of having a generate button for our completed story, we could have a reset button that resets the board for us.
This can be done a few different ways, but let's reuse a pattern we've already established. Let's create a variable to hold a button just like we did for our story. This reset button will need an id and an onclick
event because we want something to happen when the button is clicked. Let's add this logic in the submitMadLibs
function.
let resetButton = `<button id="madlibs-reset" onclick="resetMadLibs()">Play Again</button>`;
Note: Just another reminder to make sure your resetButton
string uses backticks (`) and not single or double quotes!
Now, we're going to use the exact same logic from earlier to add this string to the innerHTML of the completed-story
section.
storySection.innerHTML += resetButton;
Now, when we submit the Mad Libs form, not only do we have a story, we have a new button with the text "Play Again". We passed this button a function, so let's create it.
Create a new function called resetMadLibs
. Our main goals for this function are:
- Hide the completed story so that we can show the Mad Libs form again
- Reset the completed Mad Libs story
- Reset the Mad Libs form
- Show the Mad Libs form again
Let's turn these instructions into code! First, we can use the hide
class we created to hide our completed story section.
const resetMadLibs = () => {
storySection.classList.add('hide');
}
Next, to reset the MadLibs story, we can set the content within that section to an empty string. This will basically "reset" the completed-story
section to its original state.
const resetMadLibs = () => {
storySection.classList.add('hide');
storySection.innerHTML = '';
}
Then, we want to clear out the form contents that were previous input by the player. Luckily, there's reset function that we can use on our madLibsForm
variable because JavaScript recognizes this as an HTML form element.
const resetMadLibs = () => {
storySection.classList.add('hide');
storySection.innerHTML = '';
madLibsForm.reset();
}
Lastly, let's remove the hide
class from the Mad Libs form area so that it can be displayed again.
const resetMadLibs = () => {
storySection.classList.add('hide');
storySection.innerHTML = '';
madLibsForm.reset();
madLibsForm.classList.remove('hide');
}
Now, when we submit the Mad Libs form and hit Play Again, we're taken back to the input page as if we pressed the refresh button!
**7. Miscellaneous Styling **
We are nearing the end of this tutorial, but there are a few miscellaneous styling changes we should make to make this app look great! Let's open MadLibs.css
and finish this up.
- Style the Buttons: Our buttons are looking a little plain, so let's give them some style. We can target both buttons at the same time. I'm going to update the height, width, add a background color, shadows, and padding/margins.
#madlibs-submit button,
#madlibs-reset {
height: 40px;
width: 250px;
background-color: #83eaf1;
border-radius: 20px;
border: none;
padding: 10px;
box-shadow: rgba(50, 50, 93, 0.25) 0px 13px 27px -5px, rgba(0, 0, 0, 0.3) 0px 8px 16px -8px;
text-transform: uppercase;
font-weight: 700;
font-family: 'Poppins', sans-serif;
}
Next, I'm going to clean up the headers and center them.
h1, h2, h3{
margin: 0;
}
#intro{
padding: 0 5%;
}
.center{
text-align: center;
}
We've added this .center
class and targeted intro
, but in order for use to see these changes, let's head back over to MadLibs.html
and update our <header>
.
<header id="intro" class="center">
🎉 It's time to celebrate because you've just finished creating a function and beautiful Mad Libs app!
This project has been so fun to create, and it's fine as is, but there are a few enhancement that I want to share that will allow you to make this project your own. If you're thinking about adding a Mad Libs app to your portfolio, you may also think about adding some of these features.
1. Integrate a dictionary API to look up words
Use a free API to allow your users to look up words or even create a shuffle option that will insert a word if your users get stuck
2. Allow your players to choose from more than one story
Completing the same story over and over again isn't as fun as having a library of stories to pick from. Try making this project more modular and integrating more than one story for your uses to choose from.
3. Create a feature for diction that will read the completed story our loud to users
Everyone loves to hear a good story. Integrate diction to allow your users to hear the story they created.
➡️ Full YouTube Video Tutorial by Bree Hall