How To Build A Survey Form (freeCodeCamp Challenge)

by kleamerkuri
how to build a survey form css html

The second coding project of freeCodeCamp’s Responsive Web Design Projects is to build a survey form.

Since the recommendation is to give it my own personal style (and, in part, because the reference inspires very little excitement), I will make my survey about a BTS concert!

Disclaimer: This is NOT a real survey form. To any overexcited fans…I’m sorry.

This post will tackle each of the sixteen required steps to pass the project, troubleshooting and idea-ting along the way.

See the Pen Survey Form (FCC) by Klea Merkuri (@thehelpfultipper) on CodePen.

1. Title and short description

Begin by creating #main to act as our full-page container. I’m trying not to add CSS styles directly to the body to avoid “polluting” the stylesheet, per instruction.

<div id="main"></div>

This is, also, where the background image will go. Use the url() CSS function to pull the desired background image – mine’s courtesy of StubHub.

Use background-size to cover the entire container and background-position to make the center the focal point. This way, even when resizing the container, the image adjusts based on its set position.

#main {
  width: 100vw;
  height: 100vh;
  background: url("https://media.stubhubstatic.com/stubhub-catalog/d_defaultLogo.jpg/t_f-fs-0fv,q_auto:low,f_auto,c_fill,$w_280_mul_3,$h_180_mul_3/performer/1503185/e8pnscl4dfxujaaosbvu");
   background-size: cover;
   background-position: center; 
}

Add a header to the survey landing page which includes a title and short explanation as h1 and p elements respectively.

<header>
    <h1 id="title"><em>Map of the Soul</em> Survey Form</h1>
    <p id="description"><em>Thank you for being an ARMY fan - we love you!</em></p>
</header>

Tip: Don’t forget to add the required id on each container!

Then center the content of #main by specifying text-align:center.

2. Style header elements

Move <header> further from the top using padding then change the font color of header elements.

header {
  padding: 40px 0 10px 0;
  color: #3D3B3B;
}

To alter the font family, I imported the Poppins style from Google fonts using the @import CSS method and placed the rule at the top of the stylesheet.

@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400&display=swap");

Follow by specifying font-family:Poppins, sans-serif on #main.

The last thing to do is size header content by enlarging the description and reducing the space between text.

Note: I added text-shadow for some dimension so the description would “pop-out”.

#title {
  margin-bottom: 0.5rem;
  line-height: 1.2;
}

#description {
  font-size: 1.125rem;
  text-shadow: 1px 1px 1px rgb(0 0 0 / 10%);
}

Related: How To Build A Sign Up Form Using HTML, CSS, & JavaScript.

adding and styling the header element 1

3. Create a form with different elements

Time to add the objective of this challenge – aka the form. I place it in <main> and add the name, email, and age input fields.

Note: The instructions require a user to enter a name and an email so add required to the input tag for each.

Specify a type of email for the input to see an HTML5 validation error for entered emails that aren’t formatted correctly.

Similarly for age, we’d like to get a validation error if the entered input is a non-number which we can do by specifying a type of number. But here we’d also want to specify a range so an error will appear if the number exceeds or falls short of certain numbers. I set my range from min=10 to max=100.

<main>
    <form id="survey-form">
      <label for="name" id="name-label">Name</label>
      <input type="text" id="name" placeholder="Enter your name" required>

      <label for="email" id="email-label">Email</label>
      <input type="email" id="email" placeholder="Enter your email" required>

      <label for="number" id="number-label">Age (optional)</label>
      <input type="number" id="number" placeholder="Age" min=10 max=100>
    </form>
</main>

Let’s pause to style <main> real quick. Give the container width, background color, and slightly round edges.

main {
  max-width: 700px;
  margin: 10px auto;
  background-color: rgba(150, 42, 59, 0.9);
  border-radius: 5px;
  padding: 40px;
}

I use rgba(141, 117, 123, 0.9) specifically to get the transparent-like effect on the container. The first three numbers identify the color whereas the fourth number, 0.9, stands for opacity.

Tip: To convert a hex color into an rgb or rgba you can use a free converter.

Using background-color:rgb(141, 117, 123) and opacity:0.9 is NOT the same thing!

If you don’t believe me, go ahead and try it. You’ll see that setting the opacity in this way will affect not only the parent container but, also, its children – everything will have an opacity of 0.9.

We only want <main> to be somewhat transparent so setting its background color with a lower opacity is the way to go.

Insert the dropdowns, radio buttons, and textarea

Add the rest of the form elements. First, include a dropdown – it’ll be one out of two in this form.

      <label for="role">We'd love to know you better. What best describes you?</label>
      <select name="role" id="dropdown">
        <option>Select current role</option>
        <option value="student">Student</option>
        <option value="full-time-job">Full Time Job</option>
        <option value="full-time-learner">Full Time Learner</option>
        <option value="fan">Just a fan</option>
        <option value="other">Other</option>
      </select>

Second, add the radio button selection in a <fieldset> element to group the label and controls together.

Make sure the name value matches for all radio buttons to make them mutually exclusive (i.e. you can only click on one at a time).

Add the attribute checked to the first radio button choice so it’s selected (like in the reference).

And don’t forget the value attribute! It’s required to pass the test.

    <fieldset>
        <legend>Would you attend another BTS concert?</legend>

        <div>
          <input type="radio" name="attendance" value="definitely" id="definitely" checked>
          <label for="definitely">Definitely</label>
        </div>

        <div>
          <input type="radio" name="attendance" value="maybe" id="maybe">
          <label for="maybe">Maybe</label>
        </div>

        <div>
          <input type="radio" name="attendance" value="not-sure" id="not-sure">
        <label for="not-sure">Not sure</label>
        </div>
    </fieldset>

Follow with a second dropdown which I don’t think is necessary as the requirements ask for a single dropdown with the specified id. But I’m imitating the structure of the reference sample so two it is!

     <label for="song">What's your favorite <em>Map of the Soul</em> song?</label>
      <select name="song" id="song">
        <option>Select an option</option>
        <option value="pesona">Persona</option>
        <option value="boy-with-luv">Boy With Luv</option>
        <option value="make-it-right">Make It Right</option>
        <option value="my-time">My Time</option>
        <option value="black-swan">Black Swan</option>
      </select>

Similar to how we grouped the radio buttons, group the checkboxes.

      <fieldset>
        <legend>Where should our next concert take place?</legend>

        <div>
          <input type="checkbox" value="los-angeles" id="los-angeles">
          <label for="los-angeles">Los Angeles</label>
        </div>

        <div>
          <input type="checkbox" value="seoul" id="seoul">
          <label for="seoul">Seoul</label>
        </div>

        <div>
          <input type="checkbox" value="abu-dhabi" id="abu-dhabi">
          <label for="abu-dhabi">Abu Dhabi</label>
        </div>

        <div>
          <input type="checkbox" value="sydney" id="sydney">
          <label for="sydney">Sydney</label>
        </div>
      </fieldset>

I wrapped the label-input pairs for both the radio buttons and checkboxes in divs with the purpose of having each inline pair become a block-level element.

Lastly, add the textarea and button to complete the form.

      <label for="comments">Any comments or suggestions?</label>
      <textarea name="comments" id="comments" placeholder="Enter your comments here..."></textarea>

      <button type="submit" id="submit">Submit</button>

The form looks like a pretty mess but no worries. We’ll tackle the appearance next!

adding form elements in survey form 2

Styling the form elements

Begin by aligning the form content to the left and changing the display of the elements from inline to block so they take up the entire line.

form {
  text-align: left;
  color: white;
}

input, select, textarea {
  display: block;
  margin-bottom: 25px;
  margin-top: 5px;
  padding: 10px;
  border: none;
  box-sizing: border-box;
}

Get rid of the <fieldset> default styles in terms of border and padding, then make the inputs within <fieldset> inline elements so they’re next to their labels.

fieldset {
  border: none;
  padding: 0;
  margin-bottom: 25px;
}

fieldset input {
  display: inline;
  margin-bottom: 0;
}

fieldset legend {
  margin-bottom: 10px;
}

By this point, you’ve probably noticed something is off with our background. The form container is spilling out of its parent!

form container spilling out of parent 3

We can rectify the situation by addressing the height declared on #main. Go ahead and comment that out, or delete, to allow #main to fit its content. You can do the same thing for the width as well.

Next, increase the font size of the form elements, give the inputs and selects rounded edges and add styles to the textarea.

form, ::placeholder, select {
  font-size: 1.1rem;
}

input, select {
  border-radius: 5px;
}

textarea {  
  min-height: 120px;
  font-family: inherit;
  font-size: inherit;
  line-height: inherit;
}

To give certain form components, like text inputs, selects, and the textarea, full width I created a class and assigned it to each component in the HTML markup.

.full-width {
  width: 100%;
}

>> Tip <<

There’s an even easier way to selectively assign full width and that’s by using the CSS :not() selector to pick all inputs that aren’t checkboxes or radios.

input:not(input[type="checkbox"]):not(input[type="radio"]), textarea, select {
  width: 100%;
}

I chain the :not() because there are two different input types that shouldn’t have full width.

But you can’t do input:not(input[type="checkbox"]), input:not(input[type="radio"]) as your code will break. Why? Because you’ll be repeating the same selector (i.e. input) and that’s not done in CSS.

Moving on, there are two more things left for us to style – the radio buttons, checkboxes, and button.

For the radios and checkboxes, we only need to increase their size.

input[type="radio"], input[type="checkbox"] {
  width: 20px;
  height: 20px;
}

And for the button, give it full width, remove the browser default border, and add some color.

button {
  width: 100%;
  padding: 15px;
  font-size: inherit;
  background-color: #54B1CE;
  border: none;
  color: white;
  font-weight: 500;
}

One last thing, take care of the rather odd appearance on the right-hand side of the inputs where it seems the padding isn’t similar to that on the left side. This is due to the padding of the inputs themselves!

box-sizing border-box to correct width 4

The padding we added to the inputs increases the overall width of the input elements distorting the actual dimensions. To correct this, set box-sizing:border-box on <main> and for every <input>.

With the CSS box-sizing property as border-box we can control for paddings and margins so the containers aren’t spilling out of their parents.

Run the checker and pat yourself on the back – another test challenge passed! Visit GitHub for the full code.

Related: How To Build A Tribute Page (freeCodeCamp Challenge)

Related Posts