Form Styling and Design

In our guide to HTML forms we introduced all of the elements and attributes used to create various types of fields for web forms. Then, in our forms tutorial we created a reservation request form for a fictional hotel. However, our form as we left it had not been styled in any way. In this tutorial, we’ll style our form to make the best use of the available space and to improve the visual presentation of the form.

Designing Form Layout

The first thing to do is to think through the steps we want to take to improve our form. Here’s our form as we left it in our form tutorial.

There are several layout changes we can make to make better use of space. Here are the changes we will make to improve the layout of our form:

  1. Fields that currently appear on two lines should be modified to appear on a single line.
  2. We can make better use of the available space by grouping related fields and making sets of grouped fields appear side-by-side.
  3. All of the text fields, radio buttons, and checkboxes should appear aligned with each other.
  4. The radio buttons and checkboxes should all appear on the left-hand side of their respective values rather than the right-hand side.
  5. We will want our form to change based on the size of the viewport.

Here’s the code we used to create the form. This will serve as the starting point for our modifications.

<form>
  <p>First name (required):<br><input type="text" name="first_name" required></p>
  <p>Last name (required):<br><input type="text" name="last_name" required></p>
  <p>Email, required to recieve email confirmation:<br><input type="email" name="email"></p>
  <p>Phone (required):<br><input type="tel" name="phone" required></p>
  <p>Street Address or P.O. Box (required):<br><input type="text" name="address" required></p>
  <p>Apartment, Suite, or No.:<br><input type="text" name="address_2"></p>
  <p>City (required): <input type="text" name="city" required></p>
  <p>State: <select name="state" required><option value="AL">AL</option><option value="AK">AK</option>
  <option value="AZ">AZ</option><option value="AR">AR</option><option value="CA">CA</option><option value="CO">CO</option>
  <option value="CT">CT</option><option value="DE">DE</option><option value="FL">FL</option><option value="GA">GA</option>
  <option value="HI">HI</option><option value="ID">ID</option><option value="IL">IL</option><option value="IN">IN</option>
  <option value="IA">IA</option><option value="KS">KS</option><option value="KY">KY</option><option value="LA">LA</option>
  <option value="ME">ME</option><option value="MD">MD</option><option value="MA">MA</option><option value="MI">MI</option>
  <option value="MN">MN</option><option value="MS">MS</option><option value="MO">MO</option><option value="MT">MT</option>
  <option value="NE">NE</option><option value="NV">NV</option><option value="NH">NH</option><option value="NJ">NJ</option>
  <option value="NM">NM</option><option value="NY">NY</option><option value="NC">NC</option><option value="ND">ND</option>
  <option value="OH">OH</option><option value="OK">OK</option><option value="OR">OR</option><option value="PA">PA</option>
  <option value="RI">RI</option><option value="SC">SC</option><option value="SD">SD</option><option value="TN">TN</option>
  <option value="TX">TX</option><option value="UT">UT</option><option value="VT">VT</option><option value="VA">VA</option>
  <option value="WA">WA</option><option value="WV">WV</option><option value="WI">WI</option><option value="WY">WY</option>
  </select>
  <p>Date of Arrival (required): <input type="date" name="arrival" required></p>
  <p>Date of Departure (required): <input type="date" name="departure" required></p>
  <fieldset>
    <legend>Party Details</legend>
      <p>So that we may select the best room for your stay, please tell us a little about your party.</p>
      <p>Number of guests in your party (required): <input type="number" name="party_size" required></p>
      <p>Have you stayed with us before?<br>
        Yes <input type="radio" name="stayed" value="yes"><br>
        No <input type="radio" name="stayed" value="no">
      </p>      
      <p>Amenities you plan to use (select all that apply):<br>
        Room service <input type="checkbox" name="room_service"><br>
        Sofa Bed <input type="checkbox" name="sofa_bed"><br>
        Swimming Pool <input type="checkbox" name="swimming"><br>
        Spa <input type="checkbox" name="spa"><br>
        Fitness Room <input type="checkbox" name="fitness"><br>
        Wireless Internet <input type="checkbox" name="wifi"><br>
      </p>      
      <p>Preferred Bed Arrangment:        
        <select name="beds">
          <option value="one king">One King Bed</option>
          <option value="one queen">One Queen Bed</option>
          <option value="two double">Two Double Beds</option>
          <option value="two queen">Two Queen Beds</option>
          <option value="two king">Two King Beds</option>
        </select>
      </p>
  </fieldset>
  <p>Special requests<br>
    <textarea placeholder="Is there anything else you'd like to let us know about your stay?" rows="6" cols="60" name="comments"></textarea>
  </p>
  <p>Would you like to receive an occasional email with discount coupons and special offers? If so, select the following box to join our email list.
    <br><input type="checkbox" name="opt_in" value="yes">
  </p>
  <input type="submit">
</form>

Step 1: Clean Up and Organize HTML

When we originally created this form we used paragraph elements and line break to create an acceptable visual appearance. However, now that we’re going to use CSS to format the appearance of the form we will be better served to use spans and to remove the HTML line breaks. We will place any field composed of a short bit of text and an input element inside of span tags and remove all hard line breaks.

<!--Original Code-->
<p>First name (required):<br><input type="text" name="first_name" required></p>
<p>Last name (required):<br><input type="text" name="last_name" required></p>

<!--With Line Breaks Removed and Paragraphs Replaced-->
<span>First name (required): <input type="text" name="first_name" required></span>
<span>Last name (required): <input type="text" name="last_name" required></span>

We’ll continue that process throughout the rest of our HTML.

There are also a few elements that need to be rearranged. The date of arrival and departure should really be included inside of the Party Details fieldset. Let’s move them there.

Next, we need to group related fields in div elements to make them easier to manipulate as a group. We’ll create four divs:

  1. The first four fields will be grouped together into a div.
  2. The next four field are all address fields. Let’s group them together.
  3. Within the fieldset we’ll group the arrival and departure dates, party size, and repeat customer confirmation together.
  4. The preferred bed arrangement and amenities checklist will be grouped in our final div.

After creating these div elements we’ll apply a class name to each div.

<!--Example of how the first four elements will be grouped together-->
<div class="related">
  <span>First name (required): <input type="text" name="first_name" required></span>
  <span>Last name (required): <input type="text" name="last_name" required></span>
  <span>Email, required to recieve email confirmation: <input type="email" name="email"></span>
  <span>Phone (required): <input type="tel" name="phone" required></span>
</div>

The final step we want to take is to clean up some of the labels that are too long. We’ll trim the email, address, and party size field labels.

Step 2: Define Global Styles

Before creating specific styles, we want to define a few global styles for our document.

We’ll use the link element to pull in a web font and then apply the font with CSS. In addition, we’ll define our html, form, and body elements with a few high-level rules. The result will be that our form is a maximum of 1000 pixels wide and is centered in the window when the window is wider than 1000 pixels.

We also want each field, now wrapped in span tags, to take up the full available width. We’ll use the width and display properties to make that happen. However, we’ll deduct a little bit of space from the full width and apply it as padding. We also need to use the overflow property to ensure that the input elements don’t overflow the spans that contain them.

<link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
<style>
  body, form, span, select, input, textarea {
    font-family: 'Open Sans', sans-serif;
    font-size: 14px;
  }
  html {
    margin: 0;
    padding: 0;
    width: 100%;
  }
  form, body {
    margin-left: auto;
    margin-right: auto;
    max-width: 1000px;
  }
  span {
    display: block;
    margin: 5px 0;
    overflow: auto;
    padding: 0 1%;
    width: 98%;
  }
</style>

Step 3: Create a Side-by-Side Layout

The purpose of grouping related elements into divs was so that we could manipulate those elements into a side-by-side layout. We’ll now write a few rules to do just that.

First, we’ll apply a width of 50% of the form to each div element. Next, we’ll float the elements so that they lay out side-by-side. Finally, we’ll apply an overflow value of auto to ensure that the divs expand to contain all of the elements nested within them.

.related {
  width: 50%;
  float: left;
  overflow: auto;
}

Step 4: Style Full-Width Elements

Not all of the elements in our form will appear half width. The textarea and fieldset elements need to be styled to take up the full available width.

We’ll force the fieldset to display below all of the elements that come before it by using the display property with a value of block. We also need to remove the default margin and apply a padding to match the padding we applied all of the span elements. To set the width we’ll use the full width minus the padding and minus 2 pixels additional width to leave room for a 2-pixel border.

We want to match the border on the fieldset and textarea, so we’ll apply a specific border rule to the fieldset which we will also repurpose when we style the textarea.

fieldset {
  display: block;
  margin: 0;
  padding: 1%;
  width: calc(98% - 4px);
  border: 2px groove #bbb;
}

The textarea should also fill the full width. However, we need to deduct the width of padding and border from that width property. We’ll copy the border rule from our fieldset ruleset to ensure the borders are styled consistently.

textarea {
  width: calc(100% - 14px);
  padding: 5px;
  border: 2px groove #bbb;
}

Step 5: Style Input Fields

Our text and drop down fields will look a lot better if we allign them. To do this we will float them to the right of their containing span.

input, select {
  float: right;
}

Since they’re aligned with the text input elements, we also need to adjust the width of the drop down elements to match the width of the text fields.

select {
  width: 162px;
}

The easiest way to align the check boxes and radio buttons will be to align them on the left-hand side of their containing spans and to apply a right-hand margin. We’ll need to use an advanced selector to target just these two types of input elements.

input[type='checkbox'], input[type='radio'] {
  float: left;
  margin-right: 10px;
}

Our submit button was inadvertently floated when we floated the rest of our input and select elements. We will now counteract that rule and at the same time go ahead and beef up our submit button with padding and margin to make it more prominent.

input[type='submit'] {
  float: left;
  margin: 10px 0;
  padding: 10px 40px;
}

Finally, let’s round the corners of the fieldset, textarea, and submit button.

input[type='submit'], fieldset, textarea {
  border-radius: 5px;
}

Step 6: Add Responsive Sizing Rules

The last step in our styling process is to create two sets of rules that will take effect when the screen reaches certain viewport sizes. By adjusting the width of the browser window we’ve identified two breakpoints at which we need to implement different sets of rules:

  1. At 760 pixels we need to remove our side-by-side layout.
  2. At 670 pixels we need to go to a single-column layout with the input fields located below their respective labels.

We’ll write two media queries to make these changes.

The first rule will remove the side-by-side layout applied to the related div elements by forcing them full width. In addition, we’ll increase the width of all text and drop down fields at this breakpoint as well to improve form readability.

@media screen and (max-width: 760px) {
  .related {
    width: 100%;
  }
  input[type='text'], input[type='number'], input[type='date'], input[type='tel'], input[type='email'], select {
    width: 400px;
  }
}

Our final ruleset will force each text and dropdown element to drop below its label and grow to the full width of the viewport once the width of the browser window drops to 670 pixels. However, when we write this rule we will need to deduct 4 pixels to account for the border applied by the browser to each input field.

@media screen and (max-width: 670px) {
  input[type='text'], input[type='number'], input[type='date'], input[type='tel'], input[type='email'], select {
    width: calc(100% - 4px);
  }
}

The Finished Product

With all of those changes made, here is the resulting form. Go ahead and resize the window below by grabbing and dragging from the bottom-right corner to see how the form changes based on the size of the viewport.

Drag the bottom right corner of the frame above to view form responsiveness.

If you want to use all or part of this form on your own site, here is the final code used to produce the form visible in the window above.

<!DOCTYPE html>
<html>
  <head lang="en">
    <meta charset="UTF-8">
    <link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
    <style>
      body, form, span, select, input, textarea {
        font-family: 'Open Sans', sans-serif;
        font-size: 14px;
      }
      html {
        margin: 0;
        padding: 0;
        width: 100%;
      }
      form, body {
        margin-left: auto;
        margin-right: auto;
        max-width: 1000px;
      }
      span {
        display: block;
        margin: 5px 0;
        overflow: auto;
        padding: 0 1%;
        width: 98%;
      }
      .related {
        width: 50%;
        float: left;
        overflow: auto;
      }
      fieldset {
        display: block;
        margin: 0;
        padding: 1%;
        width: calc(98% - 4px);
        border: 2px groove #bbb;
      }
      textarea {
        width: calc(100% - 14px);
        padding: 5px;
        border: 2px groove #bbb;
      }
      input, select {
        float: right;
      }
      select {
        width: 162px;
      }
      input[type='checkbox'], input[type='radio'] {
        float: left;
        margin-right: 10px;
      }
      input[type='submit'] {
        float: left;
        margin: 10px 0;
        padding: 10px 40px;
      }
      input[type='submit'], fieldset, textarea {
        border-radius: 5px;
      }
      @media screen and (max-width: 760px) {
        .related {
          width: 100%;
        }
        input[type='text'], input[type='number'], input[type='date'], input[type='tel'], input[type='email'], select {
          width: 400px;
        }
      }
      @media screen and (max-width: 670px) {
        input[type='text'], input[type='number'], input[type='date'], input[type='tel'], input[type='email'], select {
          width: calc(100% - 4px);
        }
      }
    </style>
  </head>
  <body>
    <h1>Reservation Request Form</h1>
    <form>
      <div class="related">
        <span>First name (required): <input type="text" name="first_name" required></span>
        <span>Last name (required): <input type="text" name="last_name" required></span>
        <span>Email: <input type="email" name="email"></span>
        <span>Phone (required): <input type="tel" name="phone" required></span>
      </div>  
      <div class="related">
        <span>Address (required): <input type="text" name="address" required></span>
        <span>Apartment, Suite, or No.: <input type="text" name="address_2"></span>
        <span>City (required): <input type="text" name="city" required></span>
        <span>State: 
          <select name="state" required><option value="AL">AL</option><option value="AK">AK</option>
          <option value="AZ">AZ</option><option value="AR">AR</option><option value="CA">CA</option><option value="CO">CO</option>
          <option value="CT">CT</option><option value="DE">DE</option><option value="FL">FL</option><option value="GA">GA</option>
          <option value="HI">HI</option><option value="ID">ID</option><option value="IL">IL</option><option value="IN">IN</option>
          <option value="IA">IA</option><option value="KS">KS</option><option value="KY">KY</option><option value="LA">LA</option>
          <option value="ME">ME</option><option value="MD">MD</option><option value="MA">MA</option><option value="MI">MI</option>
          <option value="MN">MN</option><option value="MS">MS</option><option value="MO">MO</option><option value="MT">MT</option>
          <option value="NE">NE</option><option value="NV">NV</option><option value="NH">NH</option><option value="NJ">NJ</option>
          <option value="NM">NM</option><option value="NY">NY</option><option value="NC">NC</option><option value="ND">ND</option>
          <option value="OH">OH</option><option value="OK">OK</option><option value="OR">OR</option><option value="PA">PA</option>
          <option value="RI">RI</option><option value="SC">SC</option><option value="SD">SD</option><option value="TN">TN</option>
          <option value="TX">TX</option><option value="UT">UT</option><option value="VT">VT</option><option value="VA">VA</option>
          <option value="WA">WA</option><option value="WV">WV</option><option value="WI">WI</option><option value="WY">WY</option>
          </select>
        </span>
      </div>
      <fieldset>
        <legend>Party Details</legend>
          <p>So that we may select the best room for your stay, please tell us a little about your party.</p>
          <div class="related">
            <span>Date of Arrival (required): <input type="date" name="arrival" required></span>
            <span>Date of Departure (required): <input type="date" name="departure" required></span>
            <span>No. of guests (required): <input type="number" name="party_size" required></span>
            <span>Have you stayed with us before?<br>
              Yes <input type="radio" name="stayed" value="yes"><br>
              No <input type="radio" name="stayed" value="no">
            </span> 
          </div>     
          <div class="related">
            <span>Preferred Bed Arrangment:        
              <select name="beds">
                <option value="one king">One King Bed</option>
                <option value="one queen">One Queen Bed</option>
                <option value="two double">Two Double Beds</option>
                <option value="two queen">Two Queen Beds</option>
                <option value="two king">Two King Beds</option>
              </select>
            </span>
            <span>Amenities you plan to use (select all that apply):<br>
              Room Service <input type="checkbox" name="room_service"><br>
              Sofa Bed <input type="checkbox" name="sofa_bed"><br>
              Swimming Pool <input type="checkbox" name="swimming"><br>
              Spa <input type="checkbox" name="spa"><br>
              Fitness Room <input type="checkbox" name="fitness"><br>
              Wireless Internet <input type="checkbox" name="wifi"><br>
            </span>
          </div>     
      </fieldset>
      <p>Special requests</p>
      <textarea placeholder="Is there anything else you'd like to let us know about your stay?" rows="6" name="comments"></textarea>
      <span><input type="checkbox" name="opt_in" value="yes">Would you like to receive an occasional email with discount coupons and special offers? If so, select the following box to join our email list.</span>
      <span><input type="submit"></span>
    </form>
  </body>
</html>

Next Steps

The next step in the process of creating a form is to go over accessibility and usability guidelines to ensure our form will be accessible and usable to visitors using assistive technologies and older browsers.

Jon is a freelance writer, travel enthusiast, husband and father. He writes about web technologies such as WordPress, HTML, and CSS.