Booking Page and Form

Create a semantic HTML form, and get an introduction to CSS grid.

Next video loading... 5
Get Code


So far in our lessons, we've been concentrated on styling the homepage. However, we do have a second page in our site which is the booking form for our visitors to book a trip to one of our planetary destinations.

Our first step is to create the HTML for our booking page. Right now, we do have a link to our booking page which is located in our main navigation. But when we visit this, Browsersync informs us that that page does not exist. So let's create it.

To give ourselves a headstart we will copy and paste our existing index.html file and rename the copy to booking.html.

Now, from the top down, we'll make a few updates to the content.

First, in our <title> tag, we will update this to read "Booking" and then separate it with a pipe character (|), and leave the name of our business. This is for SEO purposes, and also we place the page name first so that a user who may have multiple tabs open in their browser will be able to easily identify it.

<title>Booking | Unicorn Space Tours</title>

Next, because this will now be the Booking page, we need to remove the link around "Book Now" and leave it as just static text. We also need to update our existing links for "About" and "Tours" by adding a forward slash - / - in front of the pound sign - #.

<li><a href="/#about">About</a></li>
<li><a href="/#tours">Tours</a></li>
<li>Book Now</li>

The forward slash - / - indicates that those anchor links are located at the homepage or the root of the site.

Next, we'll swap out the <h1> and paragraph tag - <p> - with updated copy specific to our booking page, but we will leave the image of the unicorn in place to retain our branding.

<h1>Book Your Tour</h1>
<p class="lead center max-line-length">Complete the booking form, and get ready for blast off!</p>

Following that, we'll go ahead and remove everything inside of the <main> element.

Let's go ahead and refresh our browser and you'll see that we now have our updated copy, the link removed in our navigation. And because we've removed all content from within main, our footer has jumped up since it is the only other thing on the page beside our header.

Let's begin to create our form. Before we move on to creating the HTML for form, you'll notice that removing the link from our "Book Now" navigation item resulted in it looking quite a bit different than the other text which remains links.

The first update to make is updating our selector it is applying our custom font and instead of scoping this font to the nav a or the link tag will change it to the li. And on save you can see the update in the font family.

nav li
font-family: "Kulim Park", sans-serif;

Thanks to the CSS cascade, updating the li allowed the anchor links to inherit that font family. We'll leave the color as black to help identify that it is no longer a link element.

OK, so back to our form HTML. Forms have a unique HTML tag that is simply <form>.

We will be adding four fields to our form and they will each follow a similar pattern.

First, we are going to choose to wrap each warm in a div with the class of .form-field. This is to aid in alignment which we will see when we begin the styling.

<div class="form-field"></div>

Then within each .form-field div, we will have a label and we will discuss the for attribute that was auto-populated in a minute. This first field will be for the visitor's first name.

<div class="form-field">
<label for="">First Name</label>

Now we need to create what is called an input field and it has been auto-populated by VS Code as a text field which is appropriate for the type of data we expect which is a simple string.

<div class="form-field">
<label for="">First Name</label>
<input type="text" name="" id="" />

Now we need to supply values for the rest of the attributes that VS Code has auto-populated for us. We can actually use the same value for each of these.

The first thing is the name attribute, and the name populated here is intended to be used as the data name that ultimately gets passed into a server to accept the form submission.

So we will use first_name to clearly identify the purpose of this data. We can also use this as the ID attribute. Now, IDs are required for input fields because the value of the ID attribute is also populated into the for attribute on the label.

<div class="form-field">
<label for="first_name">First Name</label>
<input type="text" name="first_name" id="first_name" />

Let's save and learn why that is.

Adding the for attribute to be defined as the ID on the input allows assistive technology to associate the label to the input. So when assistive technology such as a screen reader approaches this form and lands on this text input the user of the assistive technology will hear "first name, text input" which will give them awareness of what the field is and what's expected as its value. Much as a sighted user would be able to identify this by visually seeing the label in relation to the input.

Now that we saved and we have this field visible on the page, we can see we need to do a little bit of styling to give our form some space on the page. And for that we'll use our existing classes.

So on <main>, we'll add our class of wrapper which defines a max-width and also some padding. And also our class of center to help center it on the page.

<main class="wrapper center"></main>

And within our form, we'll also add our class of center in addition to our margin-v-lg class and padding-v-lg class.

<form class="center margin-v-lg padding-v-lg"></form>

We'll do some additional form specific styling in a moment, but for now, this allows us to better see the input as we apply them to the page.

Our next field will be for "Last Name" so let's do a copy of this, and simply change all instances of "First" to "Last".

<div class="form-field">
<label for="last_name">Last Name</label>
<input type="text" name="last_name" id="last_name" />

Third, we have an email field, so we'll duplicate this again and update our labels. But we also have the opportunity to update to a more helpful type. There is actually an email input type.

<div class="form-field">
<label for="email">Email</label>
<input type="email" name="email" id="email" />

Now on save you'll see that the field itself doesn't appear any different, but on certain devices, such as some mobile devices this will enable different virtual keyboards to enable easier input of the email data type.

Lastly, we want to include a multiple-choice field. So I'll go ahead and duplicate my email and we'll retain the label, we'll update it to "Tour". and instead of input, we will use a <select> input type.

<div class="form-field">
<label for="tour">Tour</label>
<select name="tour" id="tour"></select>

Similar to our other input fields, this still requires a name and ID. And we will once again use the same value for simplicity across these attributes.

Now on save, you see that we have begun a drop-down selection. In order to give the select options, there is actually an <option> tag that we will use. Now the option value will be what gets sent to the server on form submission, while the content between the option tags is what is shown to the user within the drop-down. We'll populate these with our selection of planetary tours.

<div class="form-field">
<label for="tour">Tour</label>
<select class="form-input" name="tour" id="tour">
<option>Make a selection</option>
<option value="Mars">Mars</option>
<option value="Saturn">Saturn</option>
<option value="Pluto">Pluto</option>

The first one we have left off the value selection and on save you'll see that as the first option in the list, it is automatically been made visible to the user. Without a value, this first option essentially serves as a placeholder to help indicate to the user that they need to define an option.

Because we're using this first option of "Make a selection" as an extra hint to the user that they need to select a tour, we will add the disabled and selected attribute to the option.

<option disabled selected>Make a selection</option>

And on save, you'll see that the visual inside of the drop-down has not changed, but when we open the drop-down you'll see that the first option has been greyed out because it's disabled. This enforces for the user that they must choose a planet tour option to move forward.

The last thing we need within our form is a button to be able to submit the form. So we will wrap a button element within our .form-field class. We've previously created a class of .button which will lend us some style. However, we have been using that on a link tag but in this case, we're using a button element.

<div class="form-field">
<button type="submit" class="button">Book My Tour</button>

Let's refresh, and you'll see that it has the same visual as the link buttons that we had created earlier. The important distinction between a link (<a>) and a <button> is that a link will navigate you such as between pages, whereas a button performs an action. In this case, performing the action of submitting the form. And you'll notice, we also included the type of submit which explicitly defines for the browser that this button will submit our form.

Now we'll move into our stylesheet and add a bit more design to our form fields under the heading /* Component: Form */.

We'll begin our styling by attaching to form as an element selector. And we're going to set a new display type of grid and also add a grid-gap of 24px.

form {
display: grid;
grid-gap: 24px;

On save, let's open Inspector to see what display: grid. As I hover over form, you'll see some new coloration than what we've seen before. As a reminder, the green is an indication of padding, the orange is an indication of margin. But we have a new color here - this purple which indicates, in this case, the grid-gap that we defined of 24px. grid-gap is unique to using the display value of grid, and by default, grid will layout child components in a similar fashion to block display. the main reason we chose it for our form is due to grid-gap being one of the easiest ways to define consistent spacing between elements.

Now recall, as you can also see in Inspector, that we wrapped each of our fields and our button with a div and the class of .form-field. I'm sure you've also noticed that by default our label and input are lighting up side-by-side. Before we peek at it in Inspector, can you guess why that is? Well, by default, the browser is defining both of these elements as display: inline-block which is why they are aligning next to each other rather than the input as a block following the label. We would like to change this arrangement.

Let's go ahead and open up our .form-field class. We're also going to use display: grid for our form filled but we'll use a reduced grid-gap of 8px.

.form-field {
display: grid;
grid-gap: 8px;

And on save, you can see that the orientation of the label and its input has changed, and they are now acting like block elements.

While we do want our inputs to span the available width, this is not necessary for our button. So we'll define that .form-field button elements should use another unique property of grid that is justify-self: start, whereas the default justification was stretch which was causing that spanning behavior, we've now defined that it should condense itself to the start of the grid section.

.form-field .button {
justify-self: start;

In order to style our inputs, let's add a class to all of our inputs including the select. And we'll define our class as .form-input.

We'll go ahead and copy that to the other inputs.

<!-- Leave other attributes, add the class -->
<input class="form-input" />

Now I'd like to move on to applying a bit more custom styling to the form inputs. What we'd like to do is apply one of our brand colors as the border, and as you can see, the select stands out quite a bit from the other field types. So we'll also make some other box properties more consistent, such as padding. And applying a distinct height, which is necessary for cross-browser support, and define a font size.

.form-input {
border: 1px solid #6075b0;
border-radius: 4px;
height: 2em;
padding: 0 0.5em;
font-size: 18px;

Our last element to be styled is the form label. And again, we'll use simply the element selector of label. And make a color, font-weight, and font-size adjustment.

label {
color: #150f64;
font-weight: bold;
font-size: 18px;

The last adjustment we'll make is to limit the width of the form. And we will set this on the form element itself, with a max-width of 60ch.

form {
/* existing styles */
max-width: 60ch;

ch is a unique unit that is helpful when defining widths based on the current font and font-size in use. ch is roughly equal to the width of the zero character in the current font and font size, which makes 60ch nearly equivalent to 60 characters.

If I zoom in, the last small adjustment we can see is that our button needs a couple of extra styles that were not required on the link. In particular, there's an extra border being inherited from the default browser styles.

Right above our component form, we have our button defined. Let's create a scoped style specifically on the button element that also has the class of button. And we'll set our border to none and also another improvement that we can do is enforce the cursor of pointer.

button.button {
border: none;
cursor: pointer;

So now, our borders removed, and when I hover over the button the cursor changes to the pointer cursor, which serves as an extra indication that this element is interactive.

In this lesson, we created the HTML for our booking form. And, discussed how to update the title tag be more specific to the current page, and how to adjust our navigation. We also created our entire form HTML, and importantly we learned how the for attribute needs to be defined the same as the ID of the field that is attached to in order to allow assistive technology to correctly associate the fields.

We also learned about the difference between a button versus a link element, and that a link navigates you whereas a button performs an action. And for our styles, we began to learn about the grid display type, and one of its most useful features of grid-gap to help define consistent spacing between elements.